From 27e3f5d915e96cea8c879f2476cf630ff7139437 Mon Sep 17 00:00:00 2001 From: Xiuwen Cai Date: Wed, 18 Jan 2023 08:37:32 +0000 Subject: [PATCH] Update on 18 Jan 2023. Expand to see details. 22299de Remove internal deprecated files. 2b9332f Fix ECC issues by new NAND logic 6a5eda1 Add a notice for not released file. b756fb0 Upgrade to the latest Container Images. --- README.md | 47 + common/CMakeLists.txt | 30 +- common/inc/lx_api.h | 218 ++-- common/inc/lx_user_sample.h | 21 +- common/src/fx_nand_flash_simulated_driver.c | 10 +- .../src/lx_nand_flash_256byte_ecc_compute.c | 9 +- common/src/lx_nand_flash_block_allocate.c | 97 ++ common/src/lx_nand_flash_block_data_move.c | 231 +++++ common/src/lx_nand_flash_block_find.c | 118 +++ ...et.c => lx_nand_flash_block_mapping_set.c} | 63 +- .../src/lx_nand_flash_block_obsoleted_check.c | 366 ------- common/src/lx_nand_flash_block_reclaim.c | 620 ------------ ...ite.c => lx_nand_flash_block_status_set.c} | 68 +- common/src/lx_nand_flash_data_page_copy.c | 240 +++++ common/src/lx_nand_flash_defragment.c | 36 +- common/src/lx_nand_flash_driver_block_erase.c | 49 +- .../lx_nand_flash_driver_block_status_get.c | 45 +- .../lx_nand_flash_driver_block_status_set.c | 13 +- common/src/lx_nand_flash_driver_read.c | 184 ---- ..._get.c => lx_nand_flash_erase_count_set.c} | 94 +- .../src/lx_nand_flash_extended_cache_enable.c | 130 +-- common/src/lx_nand_flash_format.c | 283 ++++++ .../src/lx_nand_flash_free_block_list_add.c | 121 +++ .../src/lx_nand_flash_logical_sector_find.c | 841 ---------------- .../src/lx_nand_flash_mapped_block_list_add.c | 121 +++ .../src/lx_nand_flash_mapped_block_list_get.c | 98 ++ .../lx_nand_flash_mapped_block_list_remove.c | 127 +++ common/src/lx_nand_flash_memory_initialize.c | 207 ++++ common/src/lx_nand_flash_metadata_allocate.c | 374 +++++++ ...pdate.c => lx_nand_flash_metadata_build.c} | 178 ++-- common/src/lx_nand_flash_metadata_write.c | 158 +++ .../lx_nand_flash_next_block_to_erase_find.c | 305 ------ common/src/lx_nand_flash_open.c | 928 +++++------------- common/src/lx_nand_flash_partial_defragment.c | 49 +- .../lx_nand_flash_physical_page_allocate.c | 396 -------- ...nd_flash_sector_mapping_cache_invalidate.c | 154 --- common/src/lx_nand_flash_sector_read.c | 176 ++-- common/src/lx_nand_flash_sector_release.c | 523 +++++++--- common/src/lx_nand_flash_sector_write.c | 605 ++++++------ common/src/lx_nand_flash_sectors_read.c | 106 ++ common/src/lx_nand_flash_sectors_release.c | 104 ++ common/src/lx_nand_flash_sectors_write.c | 107 ++ common/src/lx_nand_flash_simulator.c | 160 ++- 43 files changed, 4075 insertions(+), 4735 deletions(-) create mode 100644 common/src/lx_nand_flash_block_allocate.c create mode 100644 common/src/lx_nand_flash_block_data_move.c create mode 100644 common/src/lx_nand_flash_block_find.c rename common/src/{lx_nand_flash_driver_extra_bytes_set.c => lx_nand_flash_block_mapping_set.c} (66%) delete mode 100644 common/src/lx_nand_flash_block_obsoleted_check.c delete mode 100644 common/src/lx_nand_flash_block_reclaim.c rename common/src/{lx_nand_flash_driver_write.c => lx_nand_flash_block_status_set.c} (64%) create mode 100644 common/src/lx_nand_flash_data_page_copy.c delete mode 100644 common/src/lx_nand_flash_driver_read.c rename common/src/{lx_nand_flash_driver_extra_bytes_get.c => lx_nand_flash_erase_count_set.c} (54%) create mode 100644 common/src/lx_nand_flash_format.c create mode 100644 common/src/lx_nand_flash_free_block_list_add.c delete mode 100644 common/src/lx_nand_flash_logical_sector_find.c create mode 100644 common/src/lx_nand_flash_mapped_block_list_add.c create mode 100644 common/src/lx_nand_flash_mapped_block_list_get.c create mode 100644 common/src/lx_nand_flash_mapped_block_list_remove.c create mode 100644 common/src/lx_nand_flash_memory_initialize.c create mode 100644 common/src/lx_nand_flash_metadata_allocate.c rename common/src/{lx_nand_flash_block_full_update.c => lx_nand_flash_metadata_build.c} (50%) create mode 100644 common/src/lx_nand_flash_metadata_write.c delete mode 100644 common/src/lx_nand_flash_next_block_to_erase_find.c delete mode 100644 common/src/lx_nand_flash_physical_page_allocate.c delete mode 100644 common/src/lx_nand_flash_sector_mapping_cache_invalidate.c create mode 100644 common/src/lx_nand_flash_sectors_read.c create mode 100644 common/src/lx_nand_flash_sectors_release.c create mode 100644 common/src/lx_nand_flash_sectors_write.c diff --git a/README.md b/README.md index 2132134..17c2ab8 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,53 @@ See [Overview of Azure RTOS LevelX](https://learn.microsoft.com/azure/rtos/level The master branch has the most recent code with all new features and bug fixes. It does not represent the latest General Availability (GA) release of the library. Each official release (preview or GA) will be tagged to mark the commit and push it into the Github releases tab, e.g. `v6.2-rel`. +> When you see xx-xx-xxxx, 6.x or x.x in function header, this means the file is not officially released yet. They will be updated in the next release. See example below. +``` +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_initialize_low_level Cortex-M23/GNU */ +/* 6.x */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for any low-level processor */ +/* initialization, including setting up interrupt vectors, setting */ +/* up a periodic timer interrupt source, saving the system stack */ +/* pointer for use in ISR processing later, and finding the first */ +/* available RAM memory address for tx_application_define. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_initialize_kernel_enter ThreadX entry function */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 Scott Larson Initial Version 6.1 */ +/* xx-xx-xxxx Scott Larson Include tx_user.h, */ +/* resulting in version 6.x */ +/* */ +/**************************************************************************/ +``` + ## Component dependencies The main components of Azure RTOS are each provided in their own repository, but there are dependencies between them, as shown in the following graph. This is important to understand when setting up your builds. diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index a08604e..7981774 100755 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -4,30 +4,38 @@ target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/src/fx_nor_flash_simulator_driver.c ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_256byte_ecc_check.c ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_256byte_ecc_compute.c - ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_block_full_update.c - ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_block_obsoleted_check.c - ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_block_reclaim.c + ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_block_allocate.c + ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_block_data_move.c + ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_block_find.c + ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_block_mapping_set.c + ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_block_status_set.c ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_close.c + ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_data_page_copy.c ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_defragment.c ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_driver_block_erase.c ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_driver_block_erased_verify.c ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_driver_block_status_get.c ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_driver_block_status_set.c - ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_driver_extra_bytes_get.c - ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_driver_extra_bytes_set.c ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_driver_page_erased_verify.c - ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_driver_read.c - ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_driver_write.c + ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_erase_count_set.c ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_extended_cache_enable.c + ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_format.c + ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_free_block_list_add.c ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_initialize.c - ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_logical_sector_find.c - ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_next_block_to_erase_find.c + ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_mapped_block_list_add.c + ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_mapped_block_list_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_mapped_block_list_remove.c + ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_memory_initialize.c + ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_metadata_allocate.c + ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_metadata_build.c + ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_metadata_write.c ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_open.c ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_page_ecc_check.c ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_page_ecc_compute.c ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_partial_defragment.c - ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_physical_page_allocate.c - ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_sector_mapping_cache_invalidate.c + ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_sectors_read.c + ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_sectors_release.c + ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_sectors_write.c ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_sector_read.c ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_sector_release.c ${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_sector_write.c diff --git a/common/inc/lx_api.h b/common/inc/lx_api.h index 63bb41c..6e9ad2e 100644 --- a/common/inc/lx_api.h +++ b/common/inc/lx_api.h @@ -26,7 +26,7 @@ /* APPLICATION INTERFACE DEFINITION RELEASE */ /* */ /* lx_api.h PORTABLE C */ -/* 6.2.0 */ +/* 6.x */ /* AUTHOR */ /* */ /* William E. Lamie, Microsoft Corporation */ @@ -75,6 +75,9 @@ /* 10-31-2022 Xiuwen Cai Modified comment(s), and */ /* updated product constants, */ /* resulting in version 6.2.0 */ +/* xx-xx-xxxx Xiuwen Cai Modified comment(s), */ +/* modified NAND logic, */ +/* resulting in version 6.x */ /* */ /**************************************************************************/ @@ -149,6 +152,10 @@ typedef unsigned long long ULONG64; #define LX_MEMSET(a,b,c) memset((a),(b),(c)) #endif +#ifndef LX_MEMCPY +#define LX_MEMCPY(a,b,c) memcpy((a),(b),(c)) +#endif + /* Disable usage of ThreadX mutex in standalone mode */ #ifdef LX_THREAD_SAFE_ENABLE #undef LX_THREAD_SAFE_ENABLE @@ -161,6 +168,10 @@ typedef unsigned long long ULONG64; #else #define LX_MEMSET TX_MEMSET +#ifndef LX_MEMCPY +#include +#define LX_MEMCPY(a,b,c) memcpy((a),(b),(c)) +#endif #define LX_INTERRUPT_SAVE_AREA TX_INTERRUPT_SAVE_AREA #define LX_DISABLE TX_DISABLE @@ -206,6 +217,9 @@ typedef unsigned long long ULONG64; #define LX_NAND_ERROR_NOT_CORRECTED 7 #define LX_NO_MEMORY 8 #define LX_DISABLED 9 +#define LX_BAD_BLOCK 10 +#define LX_NO_BLOCKS 11 +#define LX_NOT_SUPPORTED 12 #define LX_SYSTEM_INVALID_FORMAT 90 #define LX_SYSTEM_INVALID_BLOCK 91 #define LX_SYSTEM_ALLOCATION_FAILED 92 @@ -275,6 +289,25 @@ typedef unsigned long long ULONG64; #define LX_NAND_FLASH_MAPPING_LIST_UPDATE_DISABLE #endif +#ifndef LX_NAND_FLASH_MAX_METADATA_BLOCKS +#define LX_NAND_FLASH_MAX_METADATA_BLOCKS 4 +#endif + +#ifndef LX_UTILITY_SHORT_SET +#define LX_UTILITY_SHORT_SET(address, value) *((USHORT*)(address)) = (USHORT)(value) +#endif + +#ifndef LX_UTILITY_LONG_SET +#define LX_UTILITY_LONG_SET(address, value) *((ULONG*)(address)) = (ULONG)(value) +#endif + +#ifndef LX_UTILITY_SHORT_GET +#define LX_UTILITY_SHORT_GET(address) (*((USHORT*)(address))) +#endif + +#ifndef LX_UTILITY_LONG_GET +#define LX_UTILITY_LONG_GET(address) (*((ULONG*)(address))) +#endif /* Define the mask for the hash index into the NAND sector mapping cache table. The sector mapping cache is divided into 4 entry pieces that are indexed by the formula: @@ -297,26 +330,60 @@ typedef unsigned long long ULONG64; #define LX_NAND_PAGE_FREE 0xFFFFFFFF #define LX_NAND_PAGE_LIST_VALID 0xF0F0F0F0 +#define LX_NAND_PAGE_TYPE_DEVICE_INFO 0x10000000u +#define LX_NAND_PAGE_TYPE_ERASE_COUNT_TABLE 0x20000000u +#define LX_NAND_PAGE_TYPE_BLOCK_MAPPING_TABLE 0x30000000u +#define LX_NAND_PAGE_TYPE_USER_DATA 0x40000000u +#define LX_NAND_PAGE_TYPE_USER_DATA_RELEASED 0x50000000u +#define LX_NAND_PAGE_TYPE_READ_COUNT_TABLE 0x60000000u +#define LX_NAND_PAGE_TYPE_PAGE_MAPPING_TABLE 0x70000000u +#define LX_NAND_PAGE_TYPE_BLOCK_STATUS_TABLE 0x80000000u +#define LX_NAND_PAGE_TYPE_BLOCK_LINK 0x90000000u +#define LX_NAND_PAGE_TYPE_USER_DATA_MASK 0x0FFFFFFFu +#define LX_NAND_PAGE_TYPE_PAGE_NUMBER_MASK 0x000000FFu -/* Define the NAND flash extra byte structure. This will be set in the spare area of each mapped physical page. */ +#define LX_NAND_PAGE_TYPE_FREE_PAGE 0xFFFFFF00u -typedef struct LX_NAND_PAGE_EXTRA_INFO_STRUCT +#define LX_NAND_BLOCK_STATUS_FULL 0x4000u +#define LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL 0x2000u +#define LX_NAND_BLOCK_STATUS_MAPPING_PRESENT 0x1000u +#define LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK 0x0FFFu +#define LX_NAND_BLOCK_STATUS_FREE 0xFFFFu +#define LX_NAND_BLOCK_STATUS_BAD 0xFF00u +#define LX_NAND_BLOCK_STATUS_ALLOCATED 0x8000u + +#define LX_NAND_BLOCK_LINK_MAIN_METADATA_OFFSET 0 +#define LX_NAND_BLOCK_LINK_BACKUP_METADATA_OFFSET 4 + +#define LX_NAND_MAX_BLOCK_COUNT 32768 +#define LX_NAND_MAX_PAGE_PER_BLOCK 4096 + + + +#define LX_NAND_BLOCK_UNMAPPED 0xFFFF + +#define LX_NAND_DEVICE_INFO_SIGNATURE1 0x76654C20 +#define LX_NAND_DEVICE_INFO_SIGNATURE2 0x20586C65 + +#define LX_NAND_DEVICE_INFO_METADATA_TYPE_MAIN 0x01 +#define LX_NAND_DEVICE_INFO_METADATA_TYPE_SECONDARY 0x02 + + + + +/* Define the NAND device information structure. This will be set in the spare area. */ + +typedef struct LX_NAND_DEVICE_INFO_STRUCT { - ULONG lx_nand_page_extra_info_logical_sector; -} LX_NAND_PAGE_EXTRA_INFO; - - -/* Define the NAND flash logical sector cache entry structure. */ - -typedef struct LX_NAND_SECTOR_MAPPING_CACHE_ENTRY_STRUCT -{ -#ifndef LX_NAND_FLASH_DIRECT_MAPPING_CACHE - ULONG lx_nand_sector_mapping_cache_logical_sector; -#endif - USHORT lx_nand_sector_mapping_cache_block; - USHORT lx_nand_sector_mapping_cache_page; -} LX_NAND_SECTOR_MAPPING_CACHE_ENTRY; - + ULONG lx_nand_device_info_signature1; + ULONG lx_nand_device_info_signature2; + ULONG lx_nand_device_info_major_version; + ULONG lx_nand_device_info_minor_version; + ULONG lx_nand_device_info_patch_version; + ULONG lx_nand_device_info_metadata_block_number; + ULONG lx_nand_device_info_backup_metadata_block_number; + ULONG lx_nand_device_info_base_erase_count; +} LX_NAND_DEVICE_INFO; /* Define the NAND flash control block structure. */ @@ -331,20 +398,42 @@ typedef struct LX_NAND_FLASH_STRUCT ULONG lx_nand_flash_total_pages; ULONG lx_nand_flash_bad_blocks; - ULONG lx_nand_flash_free_pages; - ULONG lx_nand_flash_mapped_pages; - ULONG lx_nand_flash_obsolete_pages; - ULONG lx_nand_flash_minimum_erase_count; - ULONG lx_nand_flash_maximum_erase_count; - ULONG lx_nand_flash_free_block_search; - ULONG lx_nand_flash_found_block_search; - ULONG lx_nand_flash_found_page_search; + ULONG lx_nand_flash_base_erase_count; - ULONG lx_nand_flash_max_mapped_sector; ULONG lx_nand_flash_page_corrections; ULONG lx_nand_flash_last_block_correction; ULONG lx_nand_flash_last_page_correction; + USHORT *lx_nand_flash_block_mapping_table; + ULONG lx_nand_flash_block_mapping_table_size; + USHORT *lx_nand_flash_block_status_table; + ULONG lx_nand_flash_block_status_table_size; + UCHAR *lx_nand_flash_erase_count_table; + ULONG lx_nand_flash_erase_count_table_size; + USHORT *lx_nand_flash_block_list; + ULONG lx_nand_flash_block_list_size; + ULONG lx_nand_flash_free_block_list_tail; + ULONG lx_nand_flash_mapped_block_list_head; + + ULONG lx_nand_flash_metadata_block_number; + ULONG lx_nand_flash_metadata_block_number_current; + ULONG lx_nand_flash_metadata_block_number_next; + ULONG lx_nand_flash_metadata_block_current_page; + ULONG lx_nand_flash_metadata_block_count; + USHORT lx_nand_flash_metadata_block[LX_NAND_FLASH_MAX_METADATA_BLOCKS]; + + ULONG lx_nand_flash_backup_metadata_block_number; + ULONG lx_nand_flash_backup_metadata_block_number_current; + ULONG lx_nand_flash_backup_metadata_block_number_next; + ULONG lx_nand_flash_backup_metadata_block_current_page; + USHORT lx_nand_flash_backup_metadata_block[LX_NAND_FLASH_MAX_METADATA_BLOCKS]; + + ULONG lx_nand_flash_spare_data1_offset; + ULONG lx_nand_flash_spare_data1_length; + ULONG lx_nand_flash_spare_data2_offset; + ULONG lx_nand_flash_spare_data2_length; + ULONG lx_nand_flash_spare_total_length; + ULONG lx_nand_flash_diagnostic_system_errors; ULONG lx_nand_flash_diagnostic_system_error; ULONG lx_nand_flash_diagnostic_sector_write_requests; @@ -353,15 +442,6 @@ typedef struct LX_NAND_FLASH_STRUCT ULONG lx_nand_flash_diagnostic_page_allocates; ULONG lx_nand_flash_diagnostic_page_allocate_errors; - ULONG lx_nand_flash_diagnostic_sector_mapping_cache_hits; - ULONG lx_nand_flash_diagnostic_sector_mapping_cache_misses; - ULONG lx_nand_flash_diagnostic_page_extra_bytes_cache_hits; - ULONG lx_nand_flash_diagnostic_page_extra_bytes_cache_misses; - ULONG lx_nand_flash_diagnostic_page_0_cache_hits; - ULONG lx_nand_flash_diagnostic_page_0_cache_misses; - ULONG lx_nand_flash_diagnostic_block_status_cache_hits; - ULONG lx_nand_flash_diagnostic_block_status_cache_misses; - ULONG lx_nand_flash_diagnostic_block_reclaim_attempts; ULONG lx_nand_flash_diagnostic_block_erases; ULONG lx_nand_flash_diagnostic_block_status_gets; @@ -373,16 +453,6 @@ typedef struct LX_NAND_FLASH_STRUCT ULONG lx_nand_flash_diagnostic_moved_pages; ULONG lx_nand_flash_diagnostic_block_erased_verifies; ULONG lx_nand_flash_diagnostic_page_erased_verifies; - - ULONG lx_nand_flash_diagnostic_initial_format; - ULONG lx_nand_flash_diagnostic_erased_block; - ULONG lx_nand_flash_diagnostic_re_erase_block; - ULONG lx_nand_flash_diagnostic_page_being_obsoleted; - ULONG lx_nand_flash_diagnostic_page_obsoleted; - ULONG lx_nand_flash_diagnostic_mapping_invalid; - ULONG lx_nand_flash_diagnostic_mapping_write_interrupted; - ULONG lx_nand_flash_diagnostic_page_not_free; - ULONG lx_nand_flash_diagnostic_page_data_not_free; UINT (*lx_nand_flash_driver_read)(ULONG block, ULONG page, ULONG *destination, ULONG words); UINT (*lx_nand_flash_driver_write)(ULONG block, ULONG page, ULONG *source, ULONG words); @@ -395,18 +465,12 @@ typedef struct LX_NAND_FLASH_STRUCT UINT (*lx_nand_flash_driver_extra_bytes_set)(ULONG block, ULONG page, UCHAR *source, UINT size); UINT (*lx_nand_flash_driver_system_error)(UINT error_code, ULONG block, ULONG page); - ULONG *lx_nand_flash_page_buffer; - UINT lx_nand_flash_sector_mapping_cache_enabled; - LX_NAND_SECTOR_MAPPING_CACHE_ENTRY - lx_nand_flash_sector_mapping_cache[LX_NAND_SECTOR_MAPPING_CACHE_SIZE]; + UINT (*lx_nand_flash_driver_pages_read)(ULONG block, ULONG page, UCHAR* main_buffer, UCHAR* spare_buffer, ULONG pages); + UINT (*lx_nand_flash_driver_pages_write)(ULONG block, ULONG page, UCHAR* main_buffer, UCHAR* spare_buffer, ULONG pages); + UINT (*lx_nand_flash_driver_pages_copy)(ULONG source_block, ULONG source_page, ULONG destination_block, ULONG destination_page, ULONG pages, UCHAR* data_buffer); - - /* Define the extended cache structures for block status, page extra bytes, and block page 0 caches. The memory for these cache - extensions is optionally supplied by the application after the lx_nand_flash_open call has been made. */ - - UCHAR *lx_nand_flash_block_status_cache; - LX_NAND_PAGE_EXTRA_INFO *lx_nand_flash_page_extra_bytes_cache; - ULONG *lx_nand_flash_page_0_cache; + UCHAR *lx_nand_flash_page_buffer; + UINT lx_nand_flash_page_buffer_size; #ifdef LX_THREAD_SAFE_ENABLE @@ -570,6 +634,7 @@ extern ULONG _lx_nor_flash_opened_cou #define lx_nand_flash_defragment _lx_nand_flash_defragment #define lx_nand_flash_partial_defragment _lx_nand_flash_partial_defragment #define lx_nand_flash_extended_cache_enable _lx_nand_flash_extended_cache_enable +#define lx_nand_flash_format _lx_nand_flash_format #define lx_nand_flash_initialize _lx_nand_flash_initialize #define lx_nand_flash_open _lx_nand_flash_open #define lx_nand_flash_page_ecc_check _lx_nand_flash_page_ecc_check @@ -577,6 +642,9 @@ extern ULONG _lx_nor_flash_opened_cou #define lx_nand_flash_sector_read _lx_nand_flash_sector_read #define lx_nand_flash_sector_release _lx_nand_flash_sector_release #define lx_nand_flash_sector_write _lx_nand_flash_sector_write +#define lx_nand_flash_sectors_read _lx_nand_flash_sectors_read +#define lx_nand_flash_sectors_release _lx_nand_flash_sectors_release +#define lx_nand_flash_sectors_write _lx_nand_flash_sectors_write #define lx_nand_flash_256byte_ecc_check _lx_nand_flash_256byte_ecc_check #define lx_nand_flash_256byte_ecc_compute _lx_nand_flash_256byte_ecc_compute @@ -598,13 +666,19 @@ UINT _lx_nand_flash_close(LX_NAND_FLASH *nand_flash); UINT _lx_nand_flash_defragment(LX_NAND_FLASH *nand_flash); UINT _lx_nand_flash_initialize(void); UINT _lx_nand_flash_extended_cache_enable(LX_NAND_FLASH *nand_flash, VOID *memory, ULONG size); -UINT _lx_nand_flash_open(LX_NAND_FLASH *nand_flash, CHAR *name, UINT (*nand_driver_initialize)(LX_NAND_FLASH *)); +UINT _lx_nand_flash_format(LX_NAND_FLASH* nand_flash, CHAR* name, + UINT(*nand_driver_initialize)(LX_NAND_FLASH*), + ULONG* memory_ptr, UINT memory_size); +UINT _lx_nand_flash_open(LX_NAND_FLASH *nand_flash, CHAR *name, UINT (*nand_driver_initialize)(LX_NAND_FLASH *), ULONG* memory_ptr, UINT memory_size); UINT _lx_nand_flash_page_ecc_check(LX_NAND_FLASH *nand_flash, UCHAR *page_buffer, UCHAR *ecc_buffer); UINT _lx_nand_flash_page_ecc_compute(LX_NAND_FLASH *nand_flash, UCHAR *page_buffer, UCHAR *ecc_buffer); UINT _lx_nand_flash_partial_defragment(LX_NAND_FLASH *nand_flash, UINT max_blocks); UINT _lx_nand_flash_sector_read(LX_NAND_FLASH *nand_flash, ULONG logical_sector, VOID *buffer); UINT _lx_nand_flash_sector_release(LX_NAND_FLASH *nand_flash, ULONG logical_sector); UINT _lx_nand_flash_sector_write(LX_NAND_FLASH *nand_flash, ULONG logical_sector, VOID *buffer); +UINT _lx_nand_flash_sectors_read(LX_NAND_FLASH* nand_flash, ULONG logical_sector, VOID* buffer, ULONG sector_count); +UINT _lx_nand_flash_sectors_release(LX_NAND_FLASH* nand_flash, ULONG logical_sector, ULONG sector_count); +UINT _lx_nand_flash_sectors_write(LX_NAND_FLASH* nand_flash, ULONG logical_sector, VOID* buffer, ULONG sector_count); UINT _lx_nor_flash_close(LX_NOR_FLASH *nor_flash); UINT _lx_nor_flash_defragment(LX_NOR_FLASH *nor_flash); @@ -619,25 +693,29 @@ UINT _lx_nor_flash_sector_write(LX_NOR_FLASH *nor_flash, ULONG logical_sector /* Internal LevelX prototypes. */ -UINT _lx_nand_flash_block_full_update(LX_NAND_FLASH *nand_flash, ULONG block, ULONG erase_count); -VOID _lx_nand_flash_block_obsoleted_check(LX_NAND_FLASH *nand_flash, ULONG block); -UINT _lx_nand_flash_block_reclaim(LX_NAND_FLASH *nand_flash); - -UINT _lx_nand_flash_driver_read(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page, ULONG *destination, ULONG words); -UINT _lx_nand_flash_driver_write(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page, ULONG *source, ULONG words); UINT _lx_nand_flash_driver_block_erase(LX_NAND_FLASH *nand_flash, ULONG block, ULONG erase_count); UINT _lx_nand_flash_driver_block_erased_verify(LX_NAND_FLASH *nand_flash, ULONG block); UINT _lx_nand_flash_driver_page_erased_verify(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page); UINT _lx_nand_flash_driver_block_status_get(LX_NAND_FLASH *nand_flash, ULONG block, UCHAR *bad_block_flag); UINT _lx_nand_flash_driver_block_status_set(LX_NAND_FLASH *nand_flash, ULONG block, UCHAR bad_block_flag); -UINT _lx_nand_flash_driver_extra_bytes_get(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page, UCHAR *destination, UINT size); -UINT _lx_nand_flash_driver_extra_bytes_set(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page, UCHAR *source, UINT size); VOID _lx_nand_flash_internal_error(LX_NAND_FLASH *nand_flash, ULONG error_code); -UINT _lx_nand_flash_logical_sector_find(LX_NAND_FLASH *nand_flash, ULONG logical_sector, ULONG superceded_check, ULONG *block, ULONG *page); -UINT _lx_nand_flash_next_block_to_erase_find(LX_NAND_FLASH *nand_flash, ULONG *return_erase_block, ULONG *return_erase_count, ULONG *return_mapped_pages, ULONG *return_obsolete_pages); -UINT _lx_nand_flash_physical_page_allocate(LX_NAND_FLASH *nand_flash, ULONG *block, ULONG *page, ULONG *erase_count); -VOID _lx_nand_flash_sector_mapping_cache_invalidate(LX_NAND_FLASH *nand_flash, ULONG logical_sector); +UINT _lx_nand_flash_block_find(LX_NAND_FLASH *nand_flash, ULONG logical_sector, ULONG *block, USHORT *block_status); +UINT _lx_nand_flash_block_allocate(LX_NAND_FLASH *nand_flash, ULONG *block); +UINT _lx_nand_flash_block_data_move(LX_NAND_FLASH* nand_flash, ULONG new_block); +UINT _lx_nand_flash_block_status_set(LX_NAND_FLASH *nand_flash, ULONG block, ULONG block_status); +UINT _lx_nand_flash_erase_count_set(LX_NAND_FLASH* nand_flash, ULONG block, UCHAR erase_count); +UINT _lx_nand_flash_block_mapping_set(LX_NAND_FLASH* nand_flash, ULONG logical_sector, ULONG block); +UINT _lx_nand_flash_data_page_copy(LX_NAND_FLASH* nand_flash, ULONG logical_sector, ULONG source_block, USHORT src_block_status, + ULONG destination_block, USHORT* dest_block_status_ptr, ULONG sectors); +UINT _lx_nand_flash_free_block_list_add(LX_NAND_FLASH* nand_flash, ULONG block); +UINT _lx_nand_flash_mapped_block_list_add(LX_NAND_FLASH* nand_flash, ULONG block_mapping_index); +UINT _lx_nand_flash_mapped_block_list_get(LX_NAND_FLASH* nand_flash, ULONG *block_mapping_index); +UINT _lx_nand_flash_mapped_block_list_remove(LX_NAND_FLASH* nand_flash, ULONG block_mapping_index); +UINT _lx_nand_flash_memory_initialize(LX_NAND_FLASH* nand_flash, ULONG* memory_ptr, UINT memory_size); +UINT _lx_nand_flash_metadata_allocate(LX_NAND_FLASH* nand_flash); +UINT _lx_nand_flash_metadata_build(LX_NAND_FLASH* nand_flash); +UINT _lx_nand_flash_metadata_write(LX_NAND_FLASH *nand_flash, UCHAR* main_buffer, ULONG spare_value); VOID _lx_nand_flash_system_error(LX_NAND_FLASH *nand_flash, UINT error_code, ULONG block, ULONG page); UINT _lx_nand_flash_256byte_ecc_check(UCHAR *page_buffer, UCHAR *ecc_buffer); UINT _lx_nand_flash_256byte_ecc_compute(UCHAR *page_buffer, UCHAR *ecc_buffer); diff --git a/common/inc/lx_user_sample.h b/common/inc/lx_user_sample.h index 315aaf3..d466f8d 100644 --- a/common/inc/lx_user_sample.h +++ b/common/inc/lx_user_sample.h @@ -26,7 +26,7 @@ /* PORT SPECIFIC C INFORMATION RELEASE */ /* */ /* lx_user.h PORTABLE C */ -/* 6.1.7 */ +/* 6.x */ /* */ /* AUTHOR */ /* */ @@ -48,6 +48,9 @@ /* 06-02-2021 Bhupendra Naphade Modified comment(s), and */ /* added standalone support, */ /* resulting in version 6.1.7 */ +/* xx-xx-xxxx Xiuwen Cai Modified comment(s), and */ +/* added new NAND options, */ +/* resulting in version 6.x */ /* */ /**************************************************************************/ @@ -71,23 +74,13 @@ #define LX_FREE_SECTOR_DATA_VERIFY */ -/* By default this value is 128 and defines the logical sector mapping cache size. - Large values improve performance, but cost memory. The minimum size is 8 and - all values must be a power of 2. +/* By default this value is 4, which represents a maximum of 4 blocks that + can be allocated for metadata. */ /* -#define LX_NAND_SECTOR_MAPPING_CACHE_SIZE 128 +#define LX_NAND_FLASH_MAX_METADATA_BLOCKS 4 */ -/* Defined, this creates a direct mapping cache, such that there are no cache misses. - It also requires that LX_NAND_SECTOR_MAPPING_CACHE_SIZE represents the exact number - of total pages in your flash device. -*/ -/* -#define LX_NAND_FLASH_DIRECT_MAPPING_CACHE -*/ - - /* Defined, this disabled the extended NOR cache. */ /* #define LX_NOR_DISABLE_EXTENDED_CACHE diff --git a/common/src/fx_nand_flash_simulated_driver.c b/common/src/fx_nand_flash_simulated_driver.c index a06d9a3..7ec86c2 100644 --- a/common/src/fx_nand_flash_simulated_driver.c +++ b/common/src/fx_nand_flash_simulated_driver.c @@ -31,6 +31,9 @@ LX_NAND_FLASH nand_flash; +/* Memory buffer size should be at least 7 * total block count + 2 * page size, + that is 7 * 1024 + 2 * 528 = 8224 bytes */ +ULONG lx_memory_buffer[8224 / sizeof (ULONG)]; /* Define the NAND flash simulation initialization function. */ @@ -68,7 +71,7 @@ VOID _fx_nand_flash_simulator_driver(FX_MEDIA *media_ptr); /* FUNCTION RELEASE */ /* */ /* _fx_nand_simulator_driver PORTABLE C */ -/* 6.1.7 */ +/* 6.x */ /* AUTHOR */ /* */ /* William E. Lamie, Microsoft Corporation */ @@ -123,6 +126,9 @@ VOID _fx_nand_flash_simulator_driver(FX_MEDIA *media_ptr); /* resulting in version 6.1 */ /* 06-02-2021 Bhupendra Naphade Modified comment(s), */ /* resulting in version 6.1.7 */ +/* xx-xx-xxxx Xiuwen Cai Modified comment(s), */ +/* changed to use new API, */ +/* resulting in version 6.x */ /* */ /**************************************************************************/ VOID _fx_nand_flash_simulator_driver(FX_MEDIA *media_ptr) @@ -349,7 +355,7 @@ UINT status; media_ptr -> fx_media_driver_free_sector_update = FX_TRUE; /* Open the NAND flash simulation. */ - status = _lx_nand_flash_open(&nand_flash, "sim nand flash", _lx_nand_flash_simulator_initialize); + status = _lx_nand_flash_open(&nand_flash, "sim nand flash", _lx_nand_flash_simulator_initialize, lx_memory_buffer, sizeof(lx_memory_buffer)); /* Determine if the flash open was successful. */ if (status != LX_SUCCESS) diff --git a/common/src/lx_nand_flash_256byte_ecc_compute.c b/common/src/lx_nand_flash_256byte_ecc_compute.c index 3c9319f..1260f34 100644 --- a/common/src/lx_nand_flash_256byte_ecc_compute.c +++ b/common/src/lx_nand_flash_256byte_ecc_compute.c @@ -40,7 +40,7 @@ /* FUNCTION RELEASE */ /* */ /* _lx_nand_flash_256byte_ecc_compute PORTABLE C */ -/* 6.1.7 */ +/* 6.x */ /* AUTHOR */ /* */ /* William E. Lamie, Microsoft Corporation */ @@ -77,6 +77,9 @@ /* resulting in version 6.1 */ /* 06-02-2021 Bhupendra Naphade Modified comment(s), */ /* resulting in version 6.1.7 */ +/* xx-xx-xxxx Xiuwen Cai Modified comment(s), */ +/* inverted output, */ +/* resulting in version 6.x */ /* */ /**************************************************************************/ UINT _lx_nand_flash_256byte_ecc_compute(UCHAR *page_buffer, UCHAR *ecc_buffer) @@ -227,6 +230,10 @@ USHORT odd_byte_parity; /* Pack bit 0. */ ecc_buffer[(0+2)/8] = ((UCHAR)(ecc_buffer[(0+2)/8] | ((even_bit_parity >> 0) & 1) << (0+2)%8) & 0xFF); + ecc_buffer[0] = (UCHAR)~ecc_buffer[0]; + ecc_buffer[1] = (UCHAR)~ecc_buffer[1]; + ecc_buffer[2] = (UCHAR)~ecc_buffer[2]; + /* Return success! */ return(LX_SUCCESS); } diff --git a/common/src/lx_nand_flash_block_allocate.c b/common/src/lx_nand_flash_block_allocate.c new file mode 100644 index 0000000..bc5f452 --- /dev/null +++ b/common/src/lx_nand_flash_block_allocate.c @@ -0,0 +1,97 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** LevelX Component */ +/** */ +/** NAND Flash */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define LX_SOURCE_CODE + + +/* Disable ThreadX error checking. */ + +#ifndef LX_DISABLE_ERROR_CHECKING +#define LX_DISABLE_ERROR_CHECKING +#endif + + +/* Include necessary system files. */ + +#include "lx_api.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _lx_nand_flash_block_allocate PORTABLE C */ +/* 6.x */ +/* AUTHOR */ +/* */ +/* Xiuwen Cai, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function attempts to get a block in the free block list. */ +/* */ +/* INPUT */ +/* */ +/* nand_flash NAND flash instance */ +/* block Return block number */ +/* */ +/* OUTPUT */ +/* */ +/* return status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Internal LevelX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* xx-xx-xxxx Xiuwen Cai Initial Version 6.x */ +/* */ +/**************************************************************************/ +UINT _lx_nand_flash_block_allocate(LX_NAND_FLASH* nand_flash, ULONG* block) +{ + + + /* Check if the free block list is empty. */ + if (nand_flash -> lx_nand_flash_free_block_list_tail == 0) + { + + /* Empty list, return error. */ + return(LX_NO_BLOCKS); + } + + /* Remove one block from the list. */ + nand_flash -> lx_nand_flash_free_block_list_tail--; + + /* Return the block number. */ + *block = nand_flash -> lx_nand_flash_block_list[nand_flash -> lx_nand_flash_free_block_list_tail]; + + /* Return successful completion. */ + return(LX_SUCCESS); +} + diff --git a/common/src/lx_nand_flash_block_data_move.c b/common/src/lx_nand_flash_block_data_move.c new file mode 100644 index 0000000..2f65928 --- /dev/null +++ b/common/src/lx_nand_flash_block_data_move.c @@ -0,0 +1,231 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** LevelX Component */ +/** */ +/** NAND Flash */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define LX_SOURCE_CODE + + +/* Disable ThreadX error checking. */ + +#ifndef LX_DISABLE_ERROR_CHECKING +#define LX_DISABLE_ERROR_CHECKING +#endif + + +/* Include necessary system files. */ + +#include "lx_api.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _lx_nand_flash_block_data_move PORTABLE C */ +/* 6.x */ +/* AUTHOR */ +/* */ +/* Xiuwen Cai, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function finds a block with less erase count and copies pages */ +/* into new block. */ +/* */ +/* INPUT */ +/* */ +/* nand_flash NAND flash instance */ +/* new_block New block number */ +/* */ +/* OUTPUT */ +/* */ +/* return status */ +/* */ +/* CALLS */ +/* */ +/* _lx_nand_flash_mapped_block_list_get Get mapped block index */ +/* _lx_nand_flash_block_find Find the mapped block */ +/* _lx_nand_flash_data_page_copy Copy data pages */ +/* _lx_nand_flash_free_block_list_add Add free block to list */ +/* _lx_nand_flash_block_status_set Set block status */ +/* _lx_nand_flash_block_mapping_set Set block mapping */ +/* _lx_nand_flash_mapped_block_list_add Add mapped block to list */ +/* _lx_nand_flash_driver_block_erase Erase block */ +/* _lx_nand_flash_erase_count_set Set erase count */ +/* _lx_nand_flash_free_block_list_add Add free block to list */ +/* _lx_nand_flash_system_error Internal system error handler */ +/* tx_mutex_get Get thread protection */ +/* tx_mutex_put Release thread protection */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* xx-xx-xxxx Xiuwen Cai Initial Version 6.x */ +/* */ +/**************************************************************************/ +UINT _lx_nand_flash_block_data_move(LX_NAND_FLASH *nand_flash, ULONG new_block) +{ + +UINT status; +ULONG block; +USHORT block_status; +USHORT new_block_status; +ULONG block_mapping_index; + + + /* Get the mapped address to move the data. */ + status = _lx_nand_flash_mapped_block_list_get(nand_flash, &block_mapping_index); + + if (status) + { + + /* Return an error. */ + return(LX_ERROR); + } + + /* Find the block number to be moved. */ + status = _lx_nand_flash_block_find(nand_flash, block_mapping_index * nand_flash -> lx_nand_flash_pages_per_block, &block, &block_status); + + /* Check the status. */ + if (status) + { + + /* Return an error. */ + return(LX_ERROR); + } + + /* Set new block status to allocated for now. */ + new_block_status = LX_NAND_BLOCK_STATUS_ALLOCATED; + + /* Copy data from old block to new block. */ + status = _lx_nand_flash_data_page_copy(nand_flash, block_mapping_index * nand_flash -> lx_nand_flash_pages_per_block, block, block_status, new_block, &new_block_status, nand_flash -> lx_nand_flash_pages_per_block); + + /* Check the status. */ + if (status) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, new_block, 0); + + /* Return an error. */ + return(LX_ERROR); + } + + /* Check if no page was written. */ + if ((new_block_status & LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK) == 0) + { + + /* Mark the new block as free. */ + new_block_status = LX_NAND_BLOCK_STATUS_FREE; + + /* Add the new block to free list. */ + _lx_nand_flash_free_block_list_add(nand_flash, new_block); + + } + + /* Set the block status for the new block. */ + status = _lx_nand_flash_block_status_set(nand_flash, new_block, new_block_status); + + /* Check for an error from flash driver. */ + if (status) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, new_block, 0); + + /* Return an error. */ + return(LX_ERROR); + } + + /* Check if the block is actually mapped. */ + if (new_block_status == LX_NAND_BLOCK_STATUS_FREE) + { + + /* Unmap the block. */ + new_block = LX_NAND_BLOCK_UNMAPPED; + } + + /* Update block mapping. */ + _lx_nand_flash_block_mapping_set(nand_flash, block_mapping_index * nand_flash -> lx_nand_flash_pages_per_block, new_block); + + /* Check if the block is actually mapped. */ + if (new_block != LX_NAND_BLOCK_UNMAPPED) + { + + /* Add the block to mapped list. */ + _lx_nand_flash_mapped_block_list_add(nand_flash, block_mapping_index); + } + + /* Erase the old block. */ + 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); + + /* Check for an error from flash driver. */ + if (status) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, block, 0); + + /* Return an error. */ + return(LX_ERROR); + } + + /* Update the erase count for the erased block. */ + status = _lx_nand_flash_erase_count_set(nand_flash, block, (UCHAR)(nand_flash -> lx_nand_flash_erase_count_table[block] + 1)); + + /* Check for an error from flash driver. */ + if (status) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, block, 0); + + /* Return an error. */ + return(LX_ERROR); + } + + /* Set the block status to free. */ + status = _lx_nand_flash_block_status_set(nand_flash, block, LX_NAND_BLOCK_STATUS_FREE); + + /* Check for an error from flash driver. */ + if (status) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, block, 0); + + + /* Return an error. */ + return(LX_ERROR); + } + + /* Add the block to free block list. */ + status = _lx_nand_flash_free_block_list_add(nand_flash, block); + + /* Return status. */ + return(status); +} + diff --git a/common/src/lx_nand_flash_block_find.c b/common/src/lx_nand_flash_block_find.c new file mode 100644 index 0000000..a6224a0 --- /dev/null +++ b/common/src/lx_nand_flash_block_find.c @@ -0,0 +1,118 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** LevelX Component */ +/** */ +/** NAND Flash */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define LX_SOURCE_CODE + + +/* Disable ThreadX error checking. */ + +#ifndef LX_DISABLE_ERROR_CHECKING +#define LX_DISABLE_ERROR_CHECKING +#endif + + +/* Include necessary system files. */ + +#include "lx_api.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _lx_nand_flash_block_find PORTABLE C */ +/* 6.x */ +/* AUTHOR */ +/* */ +/* Xiuwen Cai, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function attempts to find the mapped block for the logical */ +/* sector in the mapping table. */ +/* */ +/* INPUT */ +/* */ +/* nand_flash NAND flash instance */ +/* logical_sector Logical sector number */ +/* superceded_check Check for page being */ +/* superceded (can happen if */ +/* on interruptions of page */ +/* write) */ +/* block Destination for block */ +/* page Destination for page */ +/* */ +/* OUTPUT */ +/* */ +/* return status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Internal LevelX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* xx-xx-xxxx Xiuwen Cai Initial Version 6.x */ +/* */ +/**************************************************************************/ +UINT _lx_nand_flash_block_find(LX_NAND_FLASH *nand_flash, ULONG logical_sector, ULONG *block, USHORT *block_status) +{ + + UINT block_mapping_index; + USHORT block_number; + + + /* Get the mapping index from logic sector address. */ + block_mapping_index = logical_sector / nand_flash -> lx_nand_flash_pages_per_block; + + /* Check the address range. */ + if (block_mapping_index > nand_flash -> lx_nand_flash_block_mapping_table_size / sizeof(*nand_flash -> lx_nand_flash_block_mapping_table)) + { + + /* Out of range, return an error. */ + return(LX_ERROR); + } + + /* Get the block number from mapping table. */ + block_number = nand_flash -> lx_nand_flash_block_mapping_table[block_mapping_index]; + + /* Check if it is mapped. */ + if (block_number != LX_NAND_BLOCK_UNMAPPED) + { + + /* Return the block status. */ + *block_status = nand_flash -> lx_nand_flash_block_status_table[block_number]; + } + + /* Return the block number. */ + *block = (ULONG)block_number; + + /* Return successful completion. */ + return(LX_SUCCESS); +} + diff --git a/common/src/lx_nand_flash_driver_extra_bytes_set.c b/common/src/lx_nand_flash_block_mapping_set.c similarity index 66% rename from common/src/lx_nand_flash_driver_extra_bytes_set.c rename to common/src/lx_nand_flash_block_mapping_set.c index 7921250..933e6a7 100644 --- a/common/src/lx_nand_flash_driver_extra_bytes_set.c +++ b/common/src/lx_nand_flash_block_mapping_set.c @@ -39,33 +39,29 @@ /* */ /* FUNCTION RELEASE */ /* */ -/* _lx_nand_flash_driver_extra_bytes_set PORTABLE C */ -/* 6.1.7 */ +/* _lx_nand_flash_block_mapping_set PORTABLE C */ +/* 6.x */ /* AUTHOR */ /* */ -/* William E. Lamie, Microsoft Corporation */ +/* Xiuwen Cai, Microsoft Corporation */ /* */ /* DESCRIPTION */ /* */ -/* This function calls the driver extra bytes set operation and */ -/* updates the internal cache. */ +/* This function sets block mappings. */ /* */ /* INPUT */ /* */ /* nand_flash NAND flash instance */ +/* logical_sector Logical sector number */ /* block Block number */ -/* page Page number */ -/* source Pointer to source extra bytes */ -/* size Number of extra bytes */ /* */ /* OUTPUT */ /* */ -/* Completion Status */ +/* return status */ /* */ /* CALLS */ /* */ -/* (lx_nand_flash_driver_extra_bytes_set) */ -/* NAND flash set extra bytes */ +/* _lx_nand_flash_metadata_write Write metadata */ /* */ /* CALLED BY */ /* */ @@ -75,43 +71,40 @@ /* */ /* DATE NAME DESCRIPTION */ /* */ -/* 05-19-2020 William E. Lamie Initial Version 6.0 */ -/* 09-30-2020 William E. Lamie Modified comment(s), */ -/* resulting in version 6.1 */ -/* 06-02-2021 Bhupendra Naphade Modified comment(s), */ -/* resulting in version 6.1.7 */ +/* xx-xx-xxxx Xiuwen Cai Initial Version 6.x */ /* */ /**************************************************************************/ -UINT _lx_nand_flash_driver_extra_bytes_set(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page, UCHAR *source, UINT size) +UINT _lx_nand_flash_block_mapping_set(LX_NAND_FLASH *nand_flash, ULONG logical_sector, ULONG block) { -ULONG cache_index; -ULONG *destination_ptr; +UINT block_mapping_index; +UCHAR page_number; UINT status; - /* Increment the page extra bytes set count. */ - nand_flash -> lx_nand_flash_diagnostic_page_extra_bytes_sets++; + /* Get the mapping index from logic sector address. */ + block_mapping_index = logical_sector / nand_flash -> lx_nand_flash_pages_per_block; - /* Call driver extra bytes set function. */ - status = (nand_flash -> lx_nand_flash_driver_extra_bytes_set)(block, page, source, size); - - /* Determine if the page extra bytes set cache is enabled. */ - if (nand_flash -> lx_nand_flash_page_extra_bytes_cache != LX_NULL) + /* Check the address range. */ + if (block_mapping_index > nand_flash -> lx_nand_flash_block_mapping_table_size / sizeof(*nand_flash -> lx_nand_flash_block_mapping_table)) { - - /* Calculate the cache index. */ - cache_index = (block * nand_flash -> lx_nand_flash_pages_per_block) + page; - /* Build destination address. */ - destination_ptr = &nand_flash -> lx_nand_flash_page_extra_bytes_cache[cache_index].lx_nand_page_extra_info_logical_sector; - - /* Now save this in the cache. */ - *destination_ptr = *((ULONG *) source); + /* Out of range, return an error. */ + return(LX_ERROR); } + /* Save the block number to mapping table. */ + nand_flash -> lx_nand_flash_block_mapping_table[block_mapping_index] = (USHORT)block; + + /* Get the page number to write. */ + page_number = (UCHAR)(block_mapping_index * sizeof(*nand_flash -> lx_nand_flash_block_mapping_table) / nand_flash -> lx_nand_flash_bytes_per_page); + + /* Save the mapping table. */ + status = _lx_nand_flash_metadata_write(nand_flash, ((UCHAR*)nand_flash -> lx_nand_flash_block_mapping_table) + + page_number * nand_flash -> lx_nand_flash_bytes_per_page, + LX_NAND_PAGE_TYPE_BLOCK_MAPPING_TABLE | page_number); + /* Return status. */ return(status); } - diff --git a/common/src/lx_nand_flash_block_obsoleted_check.c b/common/src/lx_nand_flash_block_obsoleted_check.c deleted file mode 100644 index 792e040..0000000 --- a/common/src/lx_nand_flash_block_obsoleted_check.c +++ /dev/null @@ -1,366 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** LevelX Component */ -/** */ -/** NAND Flash */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -#define LX_SOURCE_CODE - - -/* Disable ThreadX error checking. */ - -#ifndef LX_DISABLE_ERROR_CHECKING -#define LX_DISABLE_ERROR_CHECKING -#endif - - -/* Include necessary system files. */ - -#include "lx_api.h" - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _lx_nand_flash_block_obsoleted_check PORTABLE C */ -/* 6.1.9 */ -/* AUTHOR */ -/* */ -/* William E. Lamie, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks to see if the specified block is completely */ -/* obsoleted. If so, the block is reclaimed (erased) and made */ -/* available. */ -/* */ -/* INPUT */ -/* */ -/* nand_flash NAND flash instance */ -/* block Block number to check */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _lx_nand_flash_driver_block_status_get */ -/* Driver block status */ -/* _lx_nand_flash_driver_block_erase Driver block erase */ -/* _lx_nand_flash_driver_extra_bytes_get Driver get extra bytes */ -/* _lx_nand_flash_driver_block_status_set */ -/* Driver set extra bytes */ -/* _lx_nand_flash_driver_read Driver page read */ -/* _lx_nand_flash_driver_write Driver page write */ -/* _lx_nand_flash_block_reclaim Reclaim one block */ -/* _lx_nand_flash_system_error Internal system error handler */ -/* */ -/* CALLED BY */ -/* */ -/* Internal LevelX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 William E. Lamie Initial Version 6.0 */ -/* 09-30-2020 William E. Lamie Modified comment(s), */ -/* resulting in version 6.1 */ -/* 06-02-2021 Bhupendra Naphade Modified comment(s), */ -/* resulting in version 6.1.7 */ -/* 10-15-2021 Bhupendra Naphade Modified comment(s), */ -/* removed multiple write */ -/* to page 0, */ -/* resulting in version 6.1.9 */ -/* */ -/**************************************************************************/ -VOID _lx_nand_flash_block_obsoleted_check(LX_NAND_FLASH *nand_flash, ULONG block) -{ - -LX_NAND_PAGE_EXTRA_INFO extra_info; -UCHAR block_status; -ULONG *page_word_ptr; -ULONG erase_count; -ULONG j; -UINT status; - - - /* First, check to make sure this block is good. */ - status = _lx_nand_flash_driver_block_status_get(nand_flash, block, &block_status); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, block, 0); - - /* Simply return. */ - return; - } - - /* Is this block bad? */ - if (block_status != LX_NAND_GOOD_BLOCK) - { - - /* Yes, this block is bad. */ - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, block, 0); - - /* Simply return. */ - return; - } - - /* Read the extra bytes of page 0. This will tell us if the page has any valid mappings. */ - status = _lx_nand_flash_driver_extra_bytes_get(nand_flash, block, 0, (UCHAR *) &extra_info, sizeof(extra_info)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, block, 0); - - /* Simply return. */ - return; - } - - /* Determine if the block is full, since it must be full first before it can be - completely obsoleted. */ - if ((extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_BLOCK_FULL) != 0) - { - - /* This block is not full, therefore it cannot be obsoleted. */ - - /* Simply return. */ - return; - } - - /* Setup pointer to internal buffer. */ - page_word_ptr = nand_flash -> lx_nand_flash_page_buffer; - - /* Now read page 0 of the block, which has the erase count in the first 4 bytes. */ - status = _lx_nand_flash_driver_read(nand_flash, block, 0, page_word_ptr, (nand_flash -> lx_nand_flash_pages_per_block + 1)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, block, 0); - - /* Determine if the error is fatal. */ - if (status != LX_NAND_ERROR_CORRECTED) - { - - /* Simply return. */ - return; - } - } - - /* Determine if we have a valid logical sector mapping list. */ - if ((page_word_ptr[1] != LX_NAND_PAGE_FREE) && - (page_word_ptr[nand_flash -> lx_nand_flash_pages_per_block] == LX_NAND_PAGE_LIST_VALID)) - { - - /* Yes, we have a valid logical sector mapping list in page 0. */ - - /* Traverse the list to look for the logical sector. */ - for (j = 1; j < nand_flash -> lx_nand_flash_pages_per_block; j++) - { - - /* Is this entry valid? */ - if (page_word_ptr[j] & LX_NAND_PAGE_VALID) - { - - /* Read in the actual page entry to make sure this logical sector mapping is still valid. */ - status = _lx_nand_flash_driver_extra_bytes_get(nand_flash, block, j, (UCHAR *) &extra_info, sizeof(extra_info)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, block, j); - - /* Simply return. */ - return; - } - - /* Determine if the actual page is still valid. */ - if (extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_PAGE_VALID) - { - - /* If so, we found a valid page so the block isn't completely obsoleted. */ - - /* Simply return. */ - return; - } - } - } - - /* Pickup the erase count. */ - erase_count = page_word_ptr[0]; - - /* Determine if we need to reclaim blocks to balance out the erase counts. */ - if ((erase_count == nand_flash -> lx_nand_flash_maximum_erase_count) && - ((nand_flash -> lx_nand_flash_maximum_erase_count - nand_flash -> lx_nand_flash_minimum_erase_count) >= LX_NAND_FLASH_MAX_ERASE_COUNT_DELTA)) - { - - /* Attempt to reclaim one block. */ - _lx_nand_flash_block_reclaim(nand_flash); - } - else - { - - /* At this point we can reclaim the block. */ - - /* Write the erased started indication. */ - page_word_ptr[0] = LX_BLOCK_ERASE_STARTED; - status = _lx_nand_flash_driver_write(nand_flash, block, 0, page_word_ptr, LX_NAND_ERASE_COUNT_WRITE_SIZE); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, block, 0); - } - - /* Erase the entire block. */ - status = _lx_nand_flash_driver_block_erase(nand_flash, block, erase_count+1); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, block, 0); - - /* Attempt to mark this block as bad. */ - status = _lx_nand_flash_driver_block_status_set(nand_flash, block, LX_NAND_BAD_BLOCK); - - /* Check for error in setting the block status. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, block, 0); - } - - /* Increment the bad block count. */ - nand_flash -> lx_nand_flash_bad_blocks++; - - /* Update number of obsolete pages but not free pages since this block is now bad. */ - nand_flash -> lx_nand_flash_obsolete_pages = nand_flash -> lx_nand_flash_obsolete_pages - (nand_flash -> lx_nand_flash_pages_per_block - 1); - } - else - { - - /* Increment the erase count. */ - erase_count++; - - /* Determine if the new erase count exceeds the maximum. */ - if (erase_count > ((ULONG) LX_BLOCK_ERASE_COUNT_MAX)) - { - - /* Yes, erase count is in overflow. Stay at the maximum count. */ - erase_count = ((ULONG) LX_BLOCK_ERASE_COUNT_MAX); - } - - /* Determine if we need to update the maximum erase count. */ - if (erase_count > nand_flash -> lx_nand_flash_maximum_erase_count) - { - - /* Yes, a new maximum is present. */ - nand_flash -> lx_nand_flash_maximum_erase_count = erase_count; - - /* Determine if the search pointer is on this block. */ - if (nand_flash -> lx_nand_flash_free_block_search == block) - { - - /* Move to next block. */ - nand_flash -> lx_nand_flash_free_block_search++; - - /* Check for wrap condition. */ - if (nand_flash -> lx_nand_flash_free_block_search >= nand_flash -> lx_nand_flash_total_blocks) - { - - /* Reset to the beginning block. */ - nand_flash -> lx_nand_flash_free_block_search = 0; - } - } - } - - /* Set the buffer to all ones. */ - for (j = 0; j < nand_flash -> lx_nand_flash_words_per_page; j++) - { - - /* Set word to all ones. */ - page_word_ptr[j] = LX_ALL_ONES; - } - - /* Now store the erase count. */ - page_word_ptr[0] = (erase_count); - - /* Write the erase count for the block. */ - status = _lx_nand_flash_driver_write(nand_flash, block, 0, page_word_ptr, LX_NAND_ERASE_COUNT_WRITE_SIZE); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, block, 0); - - /* Attempt to mark this block as bad. */ - status = _lx_nand_flash_driver_block_status_set(nand_flash, block, LX_NAND_BAD_BLOCK); - - /* Check for error in setting the block status. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, block, 0); - - /* Simply return. */ - return; - } - - /* Increment the bad block count. */ - nand_flash -> lx_nand_flash_bad_blocks++; - - /* Update number of obsolete pages but not free pages since this block is now bad. */ - nand_flash -> lx_nand_flash_obsolete_pages = nand_flash -> lx_nand_flash_obsolete_pages - (nand_flash -> lx_nand_flash_pages_per_block - 1); - } - else - { - - /* Update parameters of this flash. */ - nand_flash -> lx_nand_flash_free_pages = nand_flash -> lx_nand_flash_free_pages + (nand_flash -> lx_nand_flash_pages_per_block - 1); - nand_flash -> lx_nand_flash_obsolete_pages = nand_flash -> lx_nand_flash_obsolete_pages - (nand_flash -> lx_nand_flash_pages_per_block - 1); - } - } - } - } -} - diff --git a/common/src/lx_nand_flash_block_reclaim.c b/common/src/lx_nand_flash_block_reclaim.c deleted file mode 100644 index 43a7b4a..0000000 --- a/common/src/lx_nand_flash_block_reclaim.c +++ /dev/null @@ -1,620 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** LevelX Component */ -/** */ -/** NAND Flash */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -#define LX_SOURCE_CODE - - -/* Disable ThreadX error checking. */ - -#ifndef LX_DISABLE_ERROR_CHECKING -#define LX_DISABLE_ERROR_CHECKING -#endif - - -/* Include necessary system files. */ - -#include "lx_api.h" - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _lx_nand_flash_block_reclaim PORTABLE C */ -/* 6.1.9 */ -/* AUTHOR */ -/* */ -/* William E. Lamie, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function reclaims one block from the NAND flash. */ -/* */ -/* INPUT */ -/* */ -/* nand_flash NAND flash instance */ -/* */ -/* OUTPUT */ -/* */ -/* return status */ -/* */ -/* CALLS */ -/* */ -/* _lx_nand_flash_driver_block_erase Driver erase block */ -/* _lx_nand_flash_driver_block_status_set */ -/* Set block status to bad */ -/* _lx_nand_flash_driver_extra_bytes_get NAND flash get extra bytes */ -/* _lx_nand_flash_driver_extra_bytes_set NAND flash set extra bytes */ -/* _lx_nand_flash_driver_write Driver flash page write */ -/* _lx_nand_flash_driver_read Driver flash page read */ -/* _lx_nand_flash_block_full_update Update page 0 with list of */ -/* mapped pages */ -/* _lx_nand_flash_next_block_to_erase_find */ -/* Find next block to erase */ -/* _lx_nand_flash_physical_page_allocate Allocate new page */ -/* _lx_nand_flash_sector_mapping_cache_invalidate */ -/* Invalidate cache entry */ -/* _lx_nand_flash_system_error Internal system error handler */ -/* */ -/* CALLED BY */ -/* */ -/* Internal LevelX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 William E. Lamie Initial Version 6.0 */ -/* 09-30-2020 William E. Lamie Modified comment(s), */ -/* resulting in version 6.1 */ -/* 06-02-2021 Bhupendra Naphade Modified comment(s), */ -/* resulting in version 6.1.7 */ -/* 08-02-2021 Bhupendra Naphade Modified comment(s), updated */ -/* obselete page count check, */ -/* resulting in version 6.1.8 */ -/* 10-15-2021 Bhupendra Naphade Modified comment(s), */ -/* removed multiple write */ -/* to page 0, */ -/* resulting in version 6.1.9 */ -/* */ -/**************************************************************************/ -UINT _lx_nand_flash_block_reclaim(LX_NAND_FLASH *nand_flash) -{ - -LX_NAND_PAGE_EXTRA_INFO old_extra_info; -LX_NAND_PAGE_EXTRA_INFO new_extra_info; -ULONG *page_word_ptr; -ULONG i; -ULONG erase_block; -ULONG erase_count; -ULONG mapped_pages; -ULONG obsolete_pages; -ULONG free_pages; -ULONG logical_sector; -ULONG new_block; -ULONG new_page; -ULONG new_erase_count; -UINT status; - - - /* Increment the reclaim attempts counter. */ - nand_flash -> lx_nand_flash_diagnostic_block_reclaim_attempts++; - - /* Determine the next block to erase. */ - _lx_nand_flash_next_block_to_erase_find(nand_flash, &erase_block, &erase_count, &mapped_pages, &obsolete_pages); - - /* Setup pointer to page memory. */ - page_word_ptr = nand_flash -> lx_nand_flash_page_buffer; - - /* Determine if the search pointer is set for this block. */ - if (nand_flash -> lx_nand_flash_free_block_search == erase_block) - { - - /* Ensure the search block is not the block we are trying to free. */ - nand_flash -> lx_nand_flash_free_block_search = erase_block + 1; - - /* Check for wrap condition. */ - if (nand_flash -> lx_nand_flash_free_block_search >= nand_flash -> lx_nand_flash_total_blocks) - nand_flash -> lx_nand_flash_free_block_search = 0; - } - - /* Determine if this block is completely obsolete. */ - if (obsolete_pages == nand_flash -> lx_nand_flash_pages_per_block - 1) - { - - /* Read page 0 of the block, which has the erase count in the first 4 bytes. */ - status = _lx_nand_flash_driver_read(nand_flash, erase_block, 0, page_word_ptr, (nand_flash -> lx_nand_flash_pages_per_block + 1)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, erase_block, 0); - } - - /* Write the erased started indication. */ - page_word_ptr[0] = LX_BLOCK_ERASE_STARTED; - status = _lx_nand_flash_driver_write(nand_flash, erase_block, 0, page_word_ptr, LX_NAND_ERASE_COUNT_WRITE_SIZE); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, erase_block, 0); - } - - /* Erase the entire block. */ - status = _lx_nand_flash_driver_block_erase(nand_flash, erase_block, erase_count+1); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, erase_block, 0); - - /* Attempt to mark this block as bad. */ - status = _lx_nand_flash_driver_block_status_set(nand_flash, erase_block, LX_NAND_BAD_BLOCK); - - /* Check for error in setting the block status. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, erase_block, 0); - } - - /* Increment the bad block count. */ - nand_flash -> lx_nand_flash_bad_blocks++; - - /* Update number of obsolete pages but not free pages since this block is now bad. */ - nand_flash -> lx_nand_flash_obsolete_pages = nand_flash -> lx_nand_flash_obsolete_pages - obsolete_pages; - } - else - { - - /* Increment the erase count. */ - erase_count++; - - /* Determine if the new erase count exceeds the maximum. */ - if (erase_count > ((ULONG) LX_BLOCK_ERASE_COUNT_MAX)) - { - - /* Yes, erase count is in overflow. Stay at the maximum count. */ - erase_count = ((ULONG) LX_BLOCK_ERASE_COUNT_MAX); - } - - /* Determine if we need to update the maximum erase count. */ - if (erase_count > nand_flash -> lx_nand_flash_maximum_erase_count) - { - - /* Yes, a new maximum is present. */ - nand_flash -> lx_nand_flash_maximum_erase_count = erase_count; - } - - /* Set the buffer to all ones. */ - for (i = 0; i < nand_flash -> lx_nand_flash_words_per_page; i++) - { - - /* Set word to all ones. */ - page_word_ptr[i] = LX_ALL_ONES; - } - - /* Now store the erase count. */ - page_word_ptr[0] = (erase_count); - - /* Write the erase count for the block. */ - status = _lx_nand_flash_driver_write(nand_flash, erase_block, 0, page_word_ptr, LX_NAND_ERASE_COUNT_WRITE_SIZE); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, erase_block, 0); - - /* Attempt to mark this block as bad. */ - status = _lx_nand_flash_driver_block_status_set(nand_flash, erase_block, LX_NAND_BAD_BLOCK); - - /* Check for error in setting the block status. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, erase_block, 0); - } - - /* Increment the bad block count. */ - nand_flash -> lx_nand_flash_bad_blocks++; - - /* Update number of obsolete pages but not free pages since this block is now bad. */ - nand_flash -> lx_nand_flash_obsolete_pages = nand_flash -> lx_nand_flash_obsolete_pages - obsolete_pages; - } - else - { - - /* Update parameters of this flash. */ - nand_flash -> lx_nand_flash_free_pages = nand_flash -> lx_nand_flash_free_pages + obsolete_pages; - nand_flash -> lx_nand_flash_obsolete_pages = nand_flash -> lx_nand_flash_obsolete_pages - obsolete_pages; - } - } - } - else - { - - /* Calculate the number of free pages in this block. */ - free_pages = nand_flash -> lx_nand_flash_pages_per_block - (obsolete_pages + mapped_pages); - - /* Determine if there are enough free pages outside of this block to reclaim this block. */ - if (mapped_pages <= (nand_flash -> lx_nand_flash_free_pages - free_pages)) - { - - /* Now search through the list to find mapped logical sectors to move. */ - for (i = 1; i < nand_flash -> lx_nand_flash_pages_per_block; i++) - { - - /* Read the logical sector mapping for this page. */ - status = _lx_nand_flash_driver_extra_bytes_get(nand_flash, erase_block, i, (UCHAR *) &old_extra_info, sizeof(old_extra_info)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, erase_block, i); - - /* Return the error. */ - return(status); - } - - /* Determine if the entry hasn't been used. */ - if (old_extra_info.lx_nand_page_extra_info_logical_sector == LX_NAND_PAGE_FREE) - { - - /* Since allocations are done sequentially in the block, we know nothing - else exists after this point. */ - break; - } - - /* Is this entry mapped? */ - if (old_extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_PAGE_VALID) - { - - /* Pickup the logical sector associated with this mapped page. */ - logical_sector = old_extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_LOGICAL_SECTOR_MASK; - - /* Invalidate the old logical sector mapping cache entry. */ - _lx_nand_flash_sector_mapping_cache_invalidate(nand_flash, logical_sector); - - /* Allocate a new page for this write. */ - _lx_nand_flash_physical_page_allocate(nand_flash, &new_block, &new_page, &new_erase_count); - - /* Check to see if the new block is the same as the block we are trying to reclaim. */ - if (new_block == erase_block) - { - - /* Yes, the new page was found in the block to be erased. Simply move the search pointer - to the block after the erase block and search for another page from there. */ - nand_flash -> lx_nand_flash_free_block_search = erase_block + 1; - - /* Check for wrap condition. */ - if (nand_flash -> lx_nand_flash_free_block_search >= nand_flash -> lx_nand_flash_total_blocks) - nand_flash -> lx_nand_flash_free_block_search = 0; - - /* Allocate new page again. */ - _lx_nand_flash_physical_page_allocate(nand_flash, &new_block, &new_page, &new_erase_count); - - /* Check again for the new page inside of the block to erase. This should be impossible, since - we check previously if there are enough free pages outside of this block needed to reclaim - this block. */ - if (new_block == erase_block) - { - - /* System error, a new page is not available outside of the erase block. - Clear the new page so we fall through to the error handling. */ - new_page = 0; - } - } - - /* Determine if the new page allocation was successful. */ - if (new_page) - { - - /* Yes, we were able to allocate a new page for the logical sector. */ - - /* Read the existing page into the internal buffer. */ - status = _lx_nand_flash_driver_read(nand_flash, erase_block, i, page_word_ptr, nand_flash -> lx_nand_flash_words_per_page); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, erase_block, i); - - /* Determine if the error is fatal. */ - if (status != LX_NAND_ERROR_CORRECTED) - { - - /* Return the error. */ - return(status); - } - } - - /* Write the logical sector data to the new page. */ - status = _lx_nand_flash_driver_write(nand_flash, new_block, new_page, page_word_ptr, nand_flash -> lx_nand_flash_words_per_page); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, new_block, new_page); - - /* Return the error. */ - return(status); - } - - /* Now deprecate the old logical sector mapping. */ - - /* Clear bit 30, which indicates this page is being superceded. */ - old_extra_info.lx_nand_page_extra_info_logical_sector = old_extra_info.lx_nand_page_extra_info_logical_sector & ~((ULONG) LX_NAND_PAGE_SUPERCEDED); - - /* Write the value back to the flash to clear bit 30. */ - status = _lx_nand_flash_driver_extra_bytes_set(nand_flash, erase_block, i, (UCHAR *) &old_extra_info, sizeof(old_extra_info)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, erase_block, i); - - /* Return the error. */ - return(status); - } - - /* Now build the new mapping entry - with the not valid bit set initially. */ - new_extra_info.lx_nand_page_extra_info_logical_sector = ((ULONG) LX_NAND_PAGE_VALID) | ((ULONG) LX_NAND_PAGE_SUPERCEDED) | ((ULONG) LX_NAND_PAGE_MAPPING_NOT_VALID) | logical_sector; - - /* Write out the new mapping entry. */ - status = _lx_nand_flash_driver_extra_bytes_set(nand_flash, new_block, new_page, (UCHAR *) &new_extra_info, sizeof(new_extra_info)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, new_block, new_page); - - /* Return the error. */ - return(status); - } - - /* Now clear the not valid bit to make this sector mapping valid. This is done because the writing of the extra bytes itself can - be interrupted and we need to make sure this can be detected when the flash is opened again. */ - new_extra_info.lx_nand_page_extra_info_logical_sector = new_extra_info.lx_nand_page_extra_info_logical_sector & ~((ULONG) LX_NAND_PAGE_MAPPING_NOT_VALID); - - /* Clear the not valid bit. */ - status = _lx_nand_flash_driver_extra_bytes_set(nand_flash, new_block, new_page, (UCHAR *) &new_extra_info, sizeof(new_extra_info)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, new_block, new_page); - - /* Return the error. */ - return(status); - } - -#ifdef LX_NAND_FLASH_DIRECT_MAPPING_CACHE - - /* Determine if this logical sector fits in the logical sector direct cache mapping. */ - if (logical_sector < LX_NAND_SECTOR_MAPPING_CACHE_SIZE) - { - - /* Remember the mapping for this logical sector. */ - nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_block = (USHORT) new_block; - nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_page = (USHORT) new_page; - } -#endif - - /* Now clear bit 31, which indicates this sector is now obsoleted. */ - old_extra_info.lx_nand_page_extra_info_logical_sector = old_extra_info.lx_nand_page_extra_info_logical_sector & ~((ULONG) LX_NAND_PAGE_VALID); - - /* Write the value back to the flash to clear bit 31. */ - status = _lx_nand_flash_driver_extra_bytes_set(nand_flash, erase_block, i, (UCHAR *) &old_extra_info, sizeof(old_extra_info)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, erase_block, i); - - /* Return the error. */ - return(status); - } - - /* Increment the number of moved pages. */ - nand_flash -> lx_nand_flash_diagnostic_moved_pages++; - - /* Determine if the new page is the last page of the block. */ - if (new_page == (nand_flash -> lx_nand_flash_pages_per_block - 1)) - { - - /* Yes, we need to update page 0 of the block with the list of mapped - pages for this block. */ - _lx_nand_flash_block_full_update(nand_flash, new_block, new_erase_count); - } - } - else - { - - /* Call system error handler - the allocation should always succeed at this point. */ - _lx_nand_flash_system_error(nand_flash, LX_SYSTEM_ALLOCATION_FAILED, erase_block, i); - - /* System error... break! */ - break; - } - - /* Decrement the number of mapped pages. */ - mapped_pages--; - - /* Determine if we are done. */ - if (mapped_pages == 0) - break; - } - } - - /* Read page 0 of the block, which has the erase count in the first 4 bytes. */ - status = _lx_nand_flash_driver_read(nand_flash, erase_block, 0, page_word_ptr, (nand_flash -> lx_nand_flash_pages_per_block + 1)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, erase_block, 0); - } - - /* Write the erased started indication. */ - page_word_ptr[0] = LX_BLOCK_ERASE_STARTED; - status = _lx_nand_flash_driver_write(nand_flash, erase_block, 0, page_word_ptr, LX_NAND_ERASE_COUNT_WRITE_SIZE); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, erase_block, 0); - } - - /* Erase the entire block. */ - status = _lx_nand_flash_driver_block_erase(nand_flash, erase_block, erase_count+1); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, erase_block, 0); - - /* Attempt to mark this block as bad. */ - status = _lx_nand_flash_driver_block_status_set(nand_flash, erase_block, LX_NAND_BAD_BLOCK); - - /* Check for error in setting the block status. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, erase_block, 0); - } - - /* Increment the bad block count. */ - nand_flash -> lx_nand_flash_bad_blocks++; - - /* Update number of obsolete pages but not free pages since this block is now bad. */ - nand_flash -> lx_nand_flash_obsolete_pages = nand_flash -> lx_nand_flash_obsolete_pages - obsolete_pages; - } - else - { - - /* Increment the erase count. */ - erase_count++; - - /* Determine if the new erase count exceeds the maximum. */ - if (erase_count > ((ULONG) LX_BLOCK_ERASE_COUNT_MAX)) - { - - /* Yes, erase count is in overflow. Stay at the maximum count. */ - erase_count = ((ULONG) LX_BLOCK_ERASE_COUNT_MAX); - } - - /* Determine if we need to update the maximum erase count. */ - if (erase_count > nand_flash -> lx_nand_flash_maximum_erase_count) - { - - /* Yes, a new maximum is present. */ - nand_flash -> lx_nand_flash_maximum_erase_count = erase_count; - } - - /* Set the buffer to all ones. */ - for (i = 0; i < nand_flash -> lx_nand_flash_words_per_page; i++) - { - - /* Set word to all ones. */ - page_word_ptr[i] = LX_ALL_ONES; - } - - /* Now store the erase count. */ - page_word_ptr[0] = (erase_count); - - /* Write the erase count for the block. */ - status = _lx_nand_flash_driver_write(nand_flash, erase_block, 0, page_word_ptr, LX_NAND_ERASE_COUNT_WRITE_SIZE); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, erase_block, 0); - - /* Attempt to mark this block as bad. */ - status = _lx_nand_flash_driver_block_status_set(nand_flash, erase_block, LX_NAND_BAD_BLOCK); - - /* Check for error in setting the block status. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, erase_block, 0); - - /* Return the error. */ - return(status); - } - - /* Increment the bad block count. */ - nand_flash -> lx_nand_flash_bad_blocks++; - - /* Update number of obsolete pages but not free pages since this block is now bad. */ - nand_flash -> lx_nand_flash_obsolete_pages = nand_flash -> lx_nand_flash_obsolete_pages - obsolete_pages; - } - else - { - - /* Update parameters of this flash. */ - nand_flash -> lx_nand_flash_free_pages = nand_flash -> lx_nand_flash_free_pages + obsolete_pages; - nand_flash -> lx_nand_flash_obsolete_pages = nand_flash -> lx_nand_flash_obsolete_pages - obsolete_pages; - } - } - } - } - - /* Return status. */ - return(LX_SUCCESS); -} - diff --git a/common/src/lx_nand_flash_driver_write.c b/common/src/lx_nand_flash_block_status_set.c similarity index 64% rename from common/src/lx_nand_flash_driver_write.c rename to common/src/lx_nand_flash_block_status_set.c index f52ec04..a100ff5 100644 --- a/common/src/lx_nand_flash_driver_write.c +++ b/common/src/lx_nand_flash_block_status_set.c @@ -39,31 +39,29 @@ /* */ /* FUNCTION RELEASE */ /* */ -/* _lx_nand_flash_driver_write PORTABLE C */ -/* 6.1.7 */ +/* _lx_nand_flash_block_status_set PORTABLE C */ +/* 6.x */ /* AUTHOR */ /* */ -/* William E. Lamie, Microsoft Corporation */ +/* Xiuwen Cai, Microsoft Corporation */ /* */ /* DESCRIPTION */ /* */ -/* This function calls the driver to write data to a NAND page. */ +/* This function sets block status. */ /* */ /* INPUT */ /* */ /* nand_flash NAND flash instance */ /* block Block number */ -/* page Page number */ -/* source Pointer to source buffer */ -/* words Number of words to write */ +/* block_status Block status */ /* */ /* OUTPUT */ /* */ -/* Completion Status */ +/* return status */ /* */ /* CALLS */ /* */ -/* (lx_nand_flash_driver_write) Driver page write */ +/* _lx_nand_flash_metadata_write Write metadata */ /* */ /* CALLED BY */ /* */ @@ -73,57 +71,25 @@ /* */ /* DATE NAME DESCRIPTION */ /* */ -/* 05-19-2020 William E. Lamie Initial Version 6.0 */ -/* 09-30-2020 William E. Lamie Modified comment(s), */ -/* resulting in version 6.1 */ -/* 06-02-2021 Bhupendra Naphade Modified comment(s), */ -/* resulting in version 6.1.7 */ +/* xx-xx-xxxx Xiuwen Cai Initial Version 6.x */ /* */ /**************************************************************************/ -UINT _lx_nand_flash_driver_write(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page, ULONG *source, ULONG words) +UINT _lx_nand_flash_block_status_set(LX_NAND_FLASH *nand_flash, ULONG block, ULONG block_status) { -ULONG cache_index; -ULONG *source_ptr; -ULONG *destination_ptr; -ULONG i; +UCHAR page_number; UINT status; - /* Determine if this is page 0. */ - if (page == 0) - { - - /* Determine if the page 0 cache is enabled. */ - if (nand_flash -> lx_nand_flash_page_0_cache != LX_NULL) - { - - /* Yes, the page 0 cache is enabled. */ + /* Save the block status to status table. */ + nand_flash -> lx_nand_flash_block_status_table[block] = (USHORT)block_status; - /* Calculate the cache index. */ - cache_index = (block * (nand_flash -> lx_nand_flash_pages_per_block + 1)); + /* Get the page number to write. */ + page_number = (UCHAR)(block * sizeof(*nand_flash -> lx_nand_flash_block_status_table) / nand_flash -> lx_nand_flash_bytes_per_page); - /* Setup destination pointer. */ - destination_ptr = &nand_flash -> lx_nand_flash_page_0_cache[cache_index]; - - /* Setup source pointer. */ - source_ptr = (ULONG *) source; - - /* Simply copy the page 0 information to the destination. */ - for (i = 0; i < (nand_flash -> lx_nand_flash_pages_per_block + 1); i++) - { - - /* Copy one word. */ - *destination_ptr++ = *source_ptr++; - } - } - } - - /* Increment the page write count. */ - nand_flash -> lx_nand_flash_diagnostic_page_writes++; - - /* Call driver write function. */ - status = (nand_flash -> lx_nand_flash_driver_write)(block, page, source, words); + /* Save the status table. */ + status = _lx_nand_flash_metadata_write(nand_flash, ((UCHAR*)nand_flash -> lx_nand_flash_block_status_table) + + page_number * nand_flash -> lx_nand_flash_bytes_per_page, LX_NAND_PAGE_TYPE_BLOCK_STATUS_TABLE | page_number); /* Return status. */ return(status); diff --git a/common/src/lx_nand_flash_data_page_copy.c b/common/src/lx_nand_flash_data_page_copy.c new file mode 100644 index 0000000..b16d175 --- /dev/null +++ b/common/src/lx_nand_flash_data_page_copy.c @@ -0,0 +1,240 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** LevelX Component */ +/** */ +/** NAND Flash */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define LX_SOURCE_CODE + + +/* Disable ThreadX error checking. */ + +#ifndef LX_DISABLE_ERROR_CHECKING +#define LX_DISABLE_ERROR_CHECKING +#endif + + +/* Include necessary system files. */ + +#include "lx_api.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _lx_nand_flash_data_page_copy PORTABLE C */ +/* 6.x */ +/* AUTHOR */ +/* */ +/* Xiuwen Cai, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function copies logical sectors into new block. */ +/* */ +/* INPUT */ +/* */ +/* nand_flash NAND flash instance */ +/* logical_sector Logical sector number */ +/* source_block Source block number */ +/* src_block_status Source block status */ +/* destination_block Destination block number */ +/* dest_block_status_ptr Pointer to destination block */ +/* status */ +/* sectors Number of sectors to copy */ +/* */ +/* OUTPUT */ +/* */ +/* return status */ +/* */ +/* CALLS */ +/* */ +/* lx_nand_flash_driver_pages_copy Driver pages copy */ +/* lx_nand_flash_driver_pages_read Driver pages read */ +/* _lx_nand_flash_system_error Internal system error handler */ +/* */ +/* CALLED BY */ +/* */ +/* Internal LevelX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* xx-xx-xxxx Xiuwen Cai Initial Version 6.x */ +/* */ +/**************************************************************************/ +UINT _lx_nand_flash_data_page_copy(LX_NAND_FLASH* nand_flash, ULONG logical_sector, ULONG source_block, USHORT src_block_status, + ULONG destination_block, USHORT* dest_block_status_ptr, ULONG sectors) +{ + +LONG source_page; +ULONG destination_page; +UINT status = LX_SUCCESS; +UINT i; +ULONG available_pages; +ULONG spare_data1; +UCHAR *spare_buffer_ptr; +ULONG dest_block_status; +ULONG number_of_pages; + + + /* Get the destination block status. */ + dest_block_status = *dest_block_status_ptr; + + /* Get the current page number of the destination block. */ + destination_page = dest_block_status & LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK; + + /* Get the available pages in the source block. */ + 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); + + /* Check if pages in the source block are sequential. */ + if (src_block_status & LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL) + { + + /* Get buffer for spare data. */ + spare_buffer_ptr = nand_flash -> lx_nand_flash_page_buffer + nand_flash -> lx_nand_flash_bytes_per_page; + + /* Loop to copy the data. */ + for (i = 0; i < sectors; i++) + { + + /* Loop to search the page. */ + for (source_page = (LONG)(available_pages - 1); source_page >= 0; source_page--) + { + + /* Read one page. */ + status = (nand_flash -> lx_nand_flash_driver_pages_read)(source_block, (ULONG)source_page, LX_NULL, spare_buffer_ptr, 1); + + /* Check for an error from flash driver. */ + if (status) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, source_block, 0); + + /* Return an error. */ + return(LX_ERROR); + } + + /* Get the spare data. */ + spare_data1 = LX_UTILITY_LONG_GET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset]); + + /* Check the address match. */ + if ((spare_data1 & LX_NAND_PAGE_TYPE_USER_DATA_MASK) == (logical_sector + i)) + { + + /* Check if the page contains valid data. */ + if ((spare_data1 & (~LX_NAND_PAGE_TYPE_USER_DATA_MASK)) == (LX_NAND_PAGE_TYPE_USER_DATA)) + { + + /* Call the driver to copy the page. */ + 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); + + /* Check for an error from flash driver. */ + if (status) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, source_block, 0); + + /* Return an error. */ + return(LX_ERROR); + } + + /* Check if the pages in destination block is still sequential. */ + if ((destination_page) != (logical_sector + i % nand_flash -> lx_nand_flash_pages_per_block)) + { + /* Mark the block status as non sequential. */ + dest_block_status |= LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL; + } + + /* Update the available pages. */ + destination_page++; + + /* Check if available page count reaches pages per block. */ + if (destination_page == nand_flash -> lx_nand_flash_pages_per_block) + { + + /* Set block full flag. */ + dest_block_status |= LX_NAND_BLOCK_STATUS_FULL; + } + } + break; + } + } + } + } + else + { + + /* Get the source page number. */ + source_page = (LONG)(logical_sector % nand_flash -> lx_nand_flash_pages_per_block); + + /* Check if the page to copy is greater than the available pages. */ + number_of_pages = ((ULONG)source_page + sectors) > available_pages ? + (available_pages > (ULONG)source_page ? available_pages - (ULONG)source_page : 0) : sectors; + + /* Check if there is any pages to be copied. */ + if (number_of_pages) + { + + /* Call the driver to copy pages. */ + 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); + + /* Check for an error from flash driver. */ + if (status) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, source_block, 0); + + /* Return an error. */ + return(LX_ERROR); + } + + /* Check if the pages in destination block is still sequential. */ + if ((ULONG)source_page != destination_page) + { + + /* Mark the block status as non sequential. */ + dest_block_status |= LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL; + } + + /* Update the available pages. */ + destination_page += number_of_pages; + + /* Check if available page count reaches pages per block. */ + if (destination_page == nand_flash -> lx_nand_flash_pages_per_block) + { + + /* Set block full flag. */ + dest_block_status |= LX_NAND_BLOCK_STATUS_FULL; + } + } + } + + /* Return the block status. */ + *dest_block_status_ptr = (USHORT)(destination_page | (dest_block_status & ~LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK)); + + /* Return status. */ + return(status); +} + diff --git a/common/src/lx_nand_flash_defragment.c b/common/src/lx_nand_flash_defragment.c index 48b2099..a0b40a7 100644 --- a/common/src/lx_nand_flash_defragment.c +++ b/common/src/lx_nand_flash_defragment.c @@ -40,7 +40,7 @@ /* FUNCTION RELEASE */ /* */ /* _lx_nand_flash_defragment PORTABLE C */ -/* 6.1.7 */ +/* 6.x */ /* AUTHOR */ /* */ /* William E. Lamie, Microsoft Corporation */ @@ -77,40 +77,18 @@ /* resulting in version 6.1 */ /* 06-02-2021 Bhupendra Naphade Modified comment(s), */ /* resulting in version 6.1.7 */ +/* xx-xx-xxxx Xiuwen Cai Modified comment(s), */ +/* deprecated this API, */ +/* resulting in version 6.x */ /* */ /**************************************************************************/ UINT _lx_nand_flash_defragment(LX_NAND_FLASH *nand_flash) { -ULONG i; + LX_PARAMETER_NOT_USED(nand_flash); - -#ifdef LX_THREAD_SAFE_ENABLE - - /* Obtain the thread safe mutex. */ - tx_mutex_get(&nand_flash -> lx_nand_flash_mutex, TX_WAIT_FOREVER); -#endif - - /* Loop for max number of blocks, while there are obsolete count. */ - for (i = 0; i < nand_flash -> lx_nand_flash_total_blocks; i++) - { - - /* Determine if there is any more defragment work. */ - if (nand_flash -> lx_nand_flash_obsolete_pages == 0) - break; - - /* Call the block reclaim function to defragment. */ - _lx_nand_flash_block_reclaim(nand_flash); - } - -#ifdef LX_THREAD_SAFE_ENABLE - - /* Release the thread safe mutex. */ - tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); -#endif - - /* Return successful completion. */ - return(LX_SUCCESS); + /* Return not supported. */ + return(LX_NOT_SUPPORTED); } diff --git a/common/src/lx_nand_flash_driver_block_erase.c b/common/src/lx_nand_flash_driver_block_erase.c index 0c34be8..bb46820 100644 --- a/common/src/lx_nand_flash_driver_block_erase.c +++ b/common/src/lx_nand_flash_driver_block_erase.c @@ -40,7 +40,7 @@ /* FUNCTION RELEASE */ /* */ /* _lx_nand_flash_driver_block_erase PORTABLE C */ -/* 6.1.7 */ +/* 6.x */ /* AUTHOR */ /* */ /* William E. Lamie, Microsoft Corporation */ @@ -76,58 +76,17 @@ /* resulting in version 6.1 */ /* 06-02-2021 Bhupendra Naphade Modified comment(s), */ /* resulting in version 6.1.7 */ +/* xx-xx-xxxx Xiuwen Cai Modified comment(s), */ +/* removed cache support, */ +/* resulting in version 6.x */ /* */ /**************************************************************************/ UINT _lx_nand_flash_driver_block_erase(LX_NAND_FLASH *nand_flash, ULONG block, ULONG erase_count) { -ULONG cache_index; -ULONG i; UINT status; - /* Determine if the block status cache is enabled. */ - if (nand_flash -> lx_nand_flash_block_status_cache != LX_NULL) - { - - /* Save the block status value in the cache. */ - nand_flash -> lx_nand_flash_block_status_cache[block] = 0xFF; - } - - /* Determine if the page extra byte cache is enabled. */ - if (nand_flash -> lx_nand_flash_page_extra_bytes_cache != LX_NULL) - { - - /* Calculate the cache index. */ - cache_index = (block * nand_flash -> lx_nand_flash_pages_per_block); - - /* Loop to clear the entries in the page extra bytes cache. */ - for (i = 0; i < nand_flash -> lx_nand_flash_pages_per_block; i++) - { - - /* Clear each cache entry. */ - nand_flash -> lx_nand_flash_page_extra_bytes_cache[cache_index+i].lx_nand_page_extra_info_logical_sector = (ULONG) 0xFFFFFFFF; - } - } - - /* Determine if the page 0 cache is enabled. */ - if (nand_flash -> lx_nand_flash_page_0_cache != LX_NULL) - { - - /* Yes, the page 0 cache is enabled. */ - - /* Build index to page 0 cache. */ - cache_index = block * (nand_flash -> lx_nand_flash_pages_per_block + 1); - - /* Clear the associated page 0 cache. */ - for (i = 0; i < (nand_flash -> lx_nand_flash_pages_per_block + 1); i++) - { - - /* Clear each cache entry. */ - nand_flash -> lx_nand_flash_page_0_cache[cache_index+i] = (ULONG) 0xFFFFFFFF; - } - } - /* Increment the block erases count. */ nand_flash -> lx_nand_flash_diagnostic_block_erases++; diff --git a/common/src/lx_nand_flash_driver_block_status_get.c b/common/src/lx_nand_flash_driver_block_status_get.c index 0644e3f..f3aac8f 100644 --- a/common/src/lx_nand_flash_driver_block_status_get.c +++ b/common/src/lx_nand_flash_driver_block_status_get.c @@ -86,48 +86,11 @@ UINT _lx_nand_flash_driver_block_status_get(LX_NAND_FLASH *nand_flash, ULONG bl UINT status; - /* Determine if the block status cache is disabled. */ - if (nand_flash -> lx_nand_flash_block_status_cache == LX_NULL) - { - - /* Increment the block status get count. */ - nand_flash -> lx_nand_flash_diagnostic_block_status_gets++; + /* Increment the block status get count. */ + nand_flash -> lx_nand_flash_diagnostic_block_status_gets++; - /* Call driver block status get function. */ - status = (nand_flash -> lx_nand_flash_driver_block_status_get)(block, bad_block_flag); - } - else - { - - /* Determine if the block status cache entry is valid. */ - if (nand_flash -> lx_nand_flash_block_status_cache[block] != 0) - { - - /* Simply return this value. */ - *bad_block_flag = nand_flash -> lx_nand_flash_block_status_cache[block]; - - /* Increment the number of status byte cache hits. */ - nand_flash -> lx_nand_flash_diagnostic_block_status_cache_hits++; - - /* Return successful status. */ - status = LX_SUCCESS; - } - else - { - - /* Increment the block status get count. */ - nand_flash -> lx_nand_flash_diagnostic_block_status_gets++; - - /* Call driver block status get function. */ - status = (nand_flash -> lx_nand_flash_driver_block_status_get)(block, bad_block_flag); - - /* Increment the number of status byte cache misses. */ - nand_flash -> lx_nand_flash_diagnostic_block_status_cache_misses++; - - /* Save the block status value in the cache. */ - nand_flash -> lx_nand_flash_block_status_cache[block] = *bad_block_flag; - } - } + /* Call driver block status get function. */ + status = (nand_flash -> lx_nand_flash_driver_block_status_get)(block, bad_block_flag); /* Return status. */ return(status); diff --git a/common/src/lx_nand_flash_driver_block_status_set.c b/common/src/lx_nand_flash_driver_block_status_set.c index 68e2ed2..2241208 100644 --- a/common/src/lx_nand_flash_driver_block_status_set.c +++ b/common/src/lx_nand_flash_driver_block_status_set.c @@ -40,7 +40,7 @@ /* FUNCTION RELEASE */ /* */ /* _lx_nand_flash_driver_block_status_set PORTABLE C */ -/* 6.1.7 */ +/* 6.x */ /* AUTHOR */ /* */ /* William E. Lamie, Microsoft Corporation */ @@ -78,6 +78,9 @@ /* resulting in version 6.1 */ /* 06-02-2021 Bhupendra Naphade Modified comment(s), */ /* resulting in version 6.1.7 */ +/* xx-xx-xxxx Xiuwen Cai Modified comment(s), */ +/* removed cache support, */ +/* resulting in version 6.x */ /* */ /**************************************************************************/ UINT _lx_nand_flash_driver_block_status_set(LX_NAND_FLASH *nand_flash, ULONG block, UCHAR bad_block_flag) @@ -86,14 +89,6 @@ UINT _lx_nand_flash_driver_block_status_set(LX_NAND_FLASH *nand_flash, ULONG bl UINT status; - /* Determine if the block status cache is enabled. */ - if (nand_flash -> lx_nand_flash_block_status_cache != LX_NULL) - { - - /* Save the block status value in the cache. */ - nand_flash -> lx_nand_flash_block_status_cache[block] = bad_block_flag; - } - /* Increment the block status set count. */ nand_flash -> lx_nand_flash_diagnostic_block_status_sets++; diff --git a/common/src/lx_nand_flash_driver_read.c b/common/src/lx_nand_flash_driver_read.c deleted file mode 100644 index c4d8d81..0000000 --- a/common/src/lx_nand_flash_driver_read.c +++ /dev/null @@ -1,184 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** LevelX Component */ -/** */ -/** NAND Flash */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -#define LX_SOURCE_CODE - - -/* Disable ThreadX error checking. */ - -#ifndef LX_DISABLE_ERROR_CHECKING -#define LX_DISABLE_ERROR_CHECKING -#endif - - -/* Include necessary system files. */ - -#include "lx_api.h" - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _lx_nand_flash_driver_read PORTABLE C */ -/* 6.1.7 */ -/* AUTHOR */ -/* */ -/* William E. Lamie, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function calls the driver to read data from a page. */ -/* */ -/* INPUT */ -/* */ -/* nand_flash NAND flash instance */ -/* block Block number */ -/* page Page number */ -/* destination Pointer to destination buffer */ -/* words Number of words to read */ -/* */ -/* OUTPUT */ -/* */ -/* Completion Status */ -/* */ -/* CALLS */ -/* */ -/* (lx_nand_flash_driver_read) Driver page read */ -/* */ -/* CALLED BY */ -/* */ -/* Internal LevelX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 William E. Lamie Initial Version 6.0 */ -/* 09-30-2020 William E. Lamie Modified comment(s), */ -/* resulting in version 6.1 */ -/* 06-02-2021 Bhupendra Naphade Modified comment(s), */ -/* resulting in version 6.1.7 */ -/* */ -/**************************************************************************/ -UINT _lx_nand_flash_driver_read(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page, ULONG *destination, ULONG words) -{ - -ULONG cache_index; -ULONG *source_ptr; -ULONG *destination_ptr; -ULONG i; -UINT status; - - - /* Determine if this is page 0. */ - if (page == 0) - { - - /* Determine if the page 0 cache is enabled. */ - if (nand_flash -> lx_nand_flash_page_0_cache != LX_NULL) - { - - /* Yes, the page 0 cache is enabled. */ - - /* Calculate the cache index. */ - cache_index = (block * (nand_flash -> lx_nand_flash_pages_per_block + 1)); - - /* Determine if this cache entry is valid. */ - if (nand_flash -> lx_nand_flash_page_0_cache[cache_index] != 0) - { - - /* Setup the destination pointer. */ - destination_ptr = (ULONG *) destination; - - /* Setup the source pointer. */ - source_ptr = &nand_flash -> lx_nand_flash_page_0_cache[cache_index]; - - /* Simply copy the page 0 information to the destination. */ - i = 0; - while (i < (nand_flash -> lx_nand_flash_pages_per_block + 1)) - { - - /* Copy one word. */ - *destination_ptr++ = *source_ptr++; - - /* Move to next word. */ - i++; - } - - /* Increment the number of page 0 cache hits. */ - nand_flash -> lx_nand_flash_diagnostic_page_0_cache_hits++; - - /* Return successful status. */ - status = LX_SUCCESS; - } - else - { - - /* Increment the page read count. */ - nand_flash -> lx_nand_flash_diagnostic_page_reads++; - - /* Increment the number of page 0 cache misses. */ - nand_flash -> lx_nand_flash_diagnostic_page_0_cache_misses++; - - /* Call driver read function. */ - status = (nand_flash -> lx_nand_flash_driver_read)(block, page, destination, words); - - /* Setup destination pointer. */ - destination_ptr = &nand_flash -> lx_nand_flash_page_0_cache[cache_index]; - - /* Setup source pointer. */ - source_ptr = (ULONG *) destination; - - /* Simply copy the page 0 information to the destination. */ - for (i = 0; i < (nand_flash -> lx_nand_flash_pages_per_block + 1); i++) - { - - /* Copy one word. */ - *destination_ptr++ = *source_ptr++; - } - } - } - else - { - - /* Increment the page read count. */ - nand_flash -> lx_nand_flash_diagnostic_page_reads++; - - /* Call driver read function. */ - status = (nand_flash -> lx_nand_flash_driver_read)(block, page, destination, words); - } - } - else - { - - /* Increment the page read count. */ - nand_flash -> lx_nand_flash_diagnostic_page_reads++; - - /* Call driver read function. */ - status = (nand_flash -> lx_nand_flash_driver_read)(block, page, destination, words); - } - - /* Return status. */ - return(status); -} - diff --git a/common/src/lx_nand_flash_driver_extra_bytes_get.c b/common/src/lx_nand_flash_erase_count_set.c similarity index 54% rename from common/src/lx_nand_flash_driver_extra_bytes_get.c rename to common/src/lx_nand_flash_erase_count_set.c index 07aef5d..5feb19b 100644 --- a/common/src/lx_nand_flash_driver_extra_bytes_get.c +++ b/common/src/lx_nand_flash_erase_count_set.c @@ -39,32 +39,29 @@ /* */ /* FUNCTION RELEASE */ /* */ -/* _lx_nand_flash_driver_extra_bytes_get PORTABLE C */ -/* 6.1.7 */ +/* _lx_nand_flash_erase_count_set PORTABLE C */ +/* 6.x */ /* AUTHOR */ /* */ -/* William E. Lamie, Microsoft Corporation */ +/* Xiuwen Cai, Microsoft Corporation */ /* */ /* DESCRIPTION */ /* */ -/* This function calls the driver to get the extra bytes of a NAND */ -/* page. */ +/* This function sets block erase count. */ /* */ /* INPUT */ /* */ /* nand_flash NAND flash instance */ /* block Block number */ -/* page Page number */ -/* destination Pointer to destination buffer */ -/* words Number of words to read */ +/* erase_count Erase count */ /* */ /* OUTPUT */ /* */ -/* Completion Status */ +/* return status */ /* */ /* CALLS */ /* */ -/* (lx_nand_flash_driver_extra_bytes_get)Get extra bytes from spare */ +/* _lx_nand_flash_metadata_write Write metadata */ /* */ /* CALLED BY */ /* */ @@ -74,79 +71,28 @@ /* */ /* DATE NAME DESCRIPTION */ /* */ -/* 05-19-2020 William E. Lamie Initial Version 6.0 */ -/* 09-30-2020 William E. Lamie Modified comment(s), */ -/* resulting in version 6.1 */ -/* 06-02-2021 Bhupendra Naphade Modified comment(s), */ -/* resulting in version 6.1.7 */ +/* xx-xx-xxxx Xiuwen Cai Initial Version 6.x */ /* */ /**************************************************************************/ -UINT _lx_nand_flash_driver_extra_bytes_get(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page, UCHAR *destination, UINT size) +UINT _lx_nand_flash_erase_count_set(LX_NAND_FLASH *nand_flash, ULONG block, UCHAR erase_count) { -ULONG *source_ptr; -ULONG *destination_ptr; -ULONG cache_index; -UINT status; +UCHAR page_number; +UINT status; - /* Determine if the page extra bytes cache is disabled. */ - if (nand_flash -> lx_nand_flash_page_extra_bytes_cache == LX_NULL) - { + /* Save the erase count to erase count table. */ + nand_flash -> lx_nand_flash_erase_count_table[block] = erase_count; - /* Increment the page extra bytes get count. */ - nand_flash -> lx_nand_flash_diagnostic_page_extra_bytes_gets++; + /* Get the page number to write. */ + page_number = (UCHAR)(block * sizeof(*nand_flash -> lx_nand_flash_erase_count_table) / nand_flash -> lx_nand_flash_bytes_per_page); - /* Call driver extra bytes get function. */ - status = (nand_flash -> lx_nand_flash_driver_extra_bytes_get)(block, page, destination, size); - } - else - { - - /* Calculate the cache index. */ - cache_index = (block * nand_flash -> lx_nand_flash_pages_per_block) + page; + /* Save the erase count table. */ + status = _lx_nand_flash_metadata_write(nand_flash, ((UCHAR*)nand_flash -> lx_nand_flash_erase_count_table) + + page_number * nand_flash -> lx_nand_flash_bytes_per_page, + LX_NAND_PAGE_TYPE_ERASE_COUNT_TABLE | page_number); - /* Setup the destination pointer. */ - destination_ptr = (ULONG *) destination; - - /* Determine if this cache entry is valid. */ - if (nand_flash -> lx_nand_flash_page_extra_bytes_cache[cache_index].lx_nand_page_extra_info_logical_sector != 0) - { - - /* Simply return this value. */ - *destination_ptr = nand_flash -> lx_nand_flash_page_extra_bytes_cache[cache_index].lx_nand_page_extra_info_logical_sector; - - /* Increment the number of page extra bytes cache hits. */ - nand_flash -> lx_nand_flash_diagnostic_page_extra_bytes_cache_hits++; - - /* Return successful status. */ - status = LX_SUCCESS; - } - else - { - - /* Increment the page extra bytes get count. */ - nand_flash -> lx_nand_flash_diagnostic_page_extra_bytes_gets++; - - /* Call driver extra bytes get function. */ - status = (nand_flash -> lx_nand_flash_driver_extra_bytes_get)(block, page, destination, size); - - /* Increment the number of page extra bytes cache misses. */ - nand_flash -> lx_nand_flash_diagnostic_page_extra_bytes_cache_misses++; - - /* Setup destination pointer. */ - destination_ptr = &nand_flash -> lx_nand_flash_page_extra_bytes_cache[cache_index].lx_nand_page_extra_info_logical_sector; - - /* Setup source pointer. */ - source_ptr = (ULONG *) destination; - - /* Save the value in the page extra bytes cache. */ - *destination_ptr = *source_ptr; - } - } - - /* Return status. */ + /* Return sector not found status. */ return(status); } - diff --git a/common/src/lx_nand_flash_extended_cache_enable.c b/common/src/lx_nand_flash_extended_cache_enable.c index ec8262d..527c03e 100644 --- a/common/src/lx_nand_flash_extended_cache_enable.c +++ b/common/src/lx_nand_flash_extended_cache_enable.c @@ -40,7 +40,7 @@ /* FUNCTION RELEASE */ /* */ /* _lx_nand_flash_extended_cache_enable PORTABLE C */ -/* 6.1.7 */ +/* 6.x */ /* AUTHOR */ /* */ /* William E. Lamie, Microsoft Corporation */ @@ -79,131 +79,19 @@ /* resulting in version 6.1 */ /* 06-02-2021 Bhupendra Naphade Modified comment(s), */ /* resulting in version 6.1.7 */ +/* xx-xx-xxxx Xiuwen Cai Modified comment(s), */ +/* deprecated this API, */ +/* resulting in version 6.x */ /* */ /**************************************************************************/ UINT _lx_nand_flash_extended_cache_enable(LX_NAND_FLASH *nand_flash, VOID *memory, ULONG size) { -UCHAR *working_ptr; -ULONG adjust_size; -ULONG i; - - - /* Setup the working pointer. */ - working_ptr = (UCHAR *) memory; + LX_PARAMETER_NOT_USED(nand_flash); + LX_PARAMETER_NOT_USED(memory); + LX_PARAMETER_NOT_USED(size); - /* Check for a NULL pointer. If NULL, disable all the caches. */ - if (working_ptr == LX_NULL) - { - - /* Disable all extended caches. */ - nand_flash -> lx_nand_flash_block_status_cache = LX_NULL; - nand_flash -> lx_nand_flash_page_extra_bytes_cache = LX_NULL; - nand_flash -> lx_nand_flash_page_0_cache = LX_NULL; - - /* Return success! */ - return(LX_SUCCESS); - } - - /* Determine if there is not enough memory for the block status cache. */ - if (size < nand_flash -> lx_nand_flash_total_blocks) - { - - /* Return an error since there is not enough memory for even the smallest - cache. */ - return(LX_ERROR); - } - - /* There is enough memory, setup the block status cache. */ - nand_flash -> lx_nand_flash_block_status_cache = working_ptr; - - /* Clear the block status cache. */ - for (i = 0; i < nand_flash -> lx_nand_flash_total_blocks; i++) - { - - /* Clear the block status cache. */ - nand_flash -> lx_nand_flash_block_status_cache[i] = ((UCHAR) 0); - } - - /* Calculate the size to adjust to achieve ULONG alignment. */ - adjust_size = nand_flash -> lx_nand_flash_total_blocks + ((ULONG) (sizeof(ULONG) - 1)); - adjust_size = (adjust_size/sizeof(ULONG)) * sizeof(ULONG); - - /* Adjust the size. */ - if (size >= adjust_size) - { - - /* Subtract the aligned size. */ - size = size - adjust_size; - } - else - { - - /* Just set size to 0. */ - size = 0; - } - - /* Determine if there is enough memory for the page extra bytes cache for each page. */ - if (size >= (nand_flash -> lx_nand_flash_total_pages * sizeof(LX_NAND_PAGE_EXTRA_INFO))) - { - - /* Yes, there is enough memory for the extra bytes cache. */ - - /* First adjust the working pointer to the start of this memory. */ - working_ptr = working_ptr + adjust_size; - - /* Setup the pointer to page extra bytes cache. */ - nand_flash -> lx_nand_flash_page_extra_bytes_cache = (LX_NAND_PAGE_EXTRA_INFO *) working_ptr; - - /* Clear the page extra bytes cache. */ - for (i = 0; i < nand_flash -> lx_nand_flash_total_pages; i++) - { - - /* Clear the block status cache. */ - nand_flash -> lx_nand_flash_page_extra_bytes_cache[i].lx_nand_page_extra_info_logical_sector = ((ULONG) 0); - } - - /* Calculate the size to adjust to achieve ULONG alignment. */ - adjust_size = (nand_flash -> lx_nand_flash_total_pages * sizeof(LX_NAND_PAGE_EXTRA_INFO) + ((ULONG) (sizeof(ULONG) - 1))); - adjust_size = (adjust_size/sizeof(ULONG)) * sizeof(ULONG); - - /* Adjust the size. */ - if (size >= adjust_size) - { - - /* Subtract the aligned size. */ - size = size - adjust_size; - } - else - { - - /* Just set size to 0. */ - size = 0; - } - } - - /* Determine if there is enough memory for the page 0 cache for each block. */ - if (size >= ((nand_flash -> lx_nand_flash_total_blocks * (nand_flash -> lx_nand_flash_pages_per_block + 1)) * sizeof(ULONG))) - { - - /* Yes, there is enough memory for the page 0 cache. */ - - /* First adjust the working pointer to the start of this memory. */ - working_ptr = working_ptr + adjust_size; - - /* Setup the pointer to page 0 cache. */ - nand_flash -> lx_nand_flash_page_0_cache = (ULONG *) working_ptr; - - /* Clear the page 0 cache. */ - for (i = 0; i < (nand_flash -> lx_nand_flash_total_blocks * (nand_flash -> lx_nand_flash_pages_per_block + 1)); i++) - { - - /* Clear the block status cache. */ - nand_flash -> lx_nand_flash_page_0_cache[i] = ((ULONG) 0); - } - } - - /* Return success. */ - return(LX_SUCCESS); + /* Return not supported. */ + return(LX_NOT_SUPPORTED); } diff --git a/common/src/lx_nand_flash_format.c b/common/src/lx_nand_flash_format.c new file mode 100644 index 0000000..903c1d2 --- /dev/null +++ b/common/src/lx_nand_flash_format.c @@ -0,0 +1,283 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** LevelX Component */ +/** */ +/** NAND Flash */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define LX_SOURCE_CODE + + +/* Disable ThreadX error checking. */ + +#ifndef LX_DISABLE_ERROR_CHECKING +#define LX_DISABLE_ERROR_CHECKING +#endif + + +/* Include necessary system files. */ + +#include "lx_api.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _lx_nand_flash_format PORTABLE C */ +/* 6.x */ +/* AUTHOR */ +/* */ +/* Xiuwen Cai, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function erases and formats a NAND flash. */ +/* */ +/* INPUT */ +/* */ +/* nand_flash NAND flash instance */ +/* name Name of NAND flash instance */ +/* nand_driver_initialize Driver initialize */ +/* memory_ptr Pointer to memory used by the */ +/* LevelX for this NAND. */ +/* memory_size Size of memory - must at least*/ +/* 7 * total block count + */ +/* 2 * page size */ +/* */ +/* OUTPUT */ +/* */ +/* return status */ +/* */ +/* CALLS */ +/* */ +/* (nand_driver_initialize) Driver initialize */ +/* LX_MEMSET Initialize memory */ +/* _lx_nand_flash_memory_initialize Initialize buffer */ +/* _lx_nand_flash_driver_block_status_get */ +/* Driver block status get */ +/* _lx_nand_flash_driver_block_status_set */ +/* Driver block status set */ +/* _lx_nand_flash_metadata_build Build metadata */ +/* _lx_nand_flash_metadata_write Write metadata */ +/* _lx_nand_flash_driver_block_erase Driver block erase */ +/* _lx_nand_flash_system_error System error handler */ +/* tx_mutex_create Create thread-safe mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* xx-xx-xxxx Xiuwen Cai Initial Version 6.x */ +/* */ +/**************************************************************************/ +UINT _lx_nand_flash_format(LX_NAND_FLASH* nand_flash, CHAR* name, + UINT(*nand_driver_initialize)(LX_NAND_FLASH*), + ULONG* memory_ptr, UINT memory_size) +{ + +ULONG block; +UCHAR block_status; +UINT status; +UCHAR *page_buffer_ptr; + + LX_PARAMETER_NOT_USED(name); + + /* Clear the NAND flash control block. */ + LX_MEMSET(nand_flash, 0, sizeof(LX_NAND_FLASH)); + + /* Call the flash driver's initialization function. */ + (nand_driver_initialize)(nand_flash); + + /* Determine if we can support this NAND flash size. */ + 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) + { + return(LX_ERROR); + } + + /* Check if it is new LevelX NAND driver. */ + 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) + { + return(LX_ERROR); + } + + /* Check the spare data length. */ + if (nand_flash -> lx_nand_flash_spare_data1_length < sizeof(ULONG)) + { + return(LX_ERROR); + } + + /* Calculate the number of words per block and per page. */ + nand_flash -> lx_nand_flash_words_per_page = (nand_flash -> lx_nand_flash_bytes_per_page / sizeof(ULONG)); + nand_flash -> lx_nand_flash_words_per_block = (nand_flash -> lx_nand_flash_words_per_page * nand_flash -> lx_nand_flash_pages_per_block); + + /* Calculate the total pages. */ + nand_flash -> lx_nand_flash_total_pages = nand_flash -> lx_nand_flash_total_blocks * nand_flash -> lx_nand_flash_pages_per_block; + + /* Initialize memory buffer. */ + status = _lx_nand_flash_memory_initialize(nand_flash, memory_ptr, memory_size); + if (status != LX_SUCCESS) + { + return(status); + } + + /* Initialize block numbers. */ + nand_flash -> lx_nand_flash_metadata_block_number = LX_NAND_BLOCK_UNMAPPED; + nand_flash -> lx_nand_flash_metadata_block_number_next = LX_NAND_BLOCK_UNMAPPED; + nand_flash -> lx_nand_flash_backup_metadata_block_number = LX_NAND_BLOCK_UNMAPPED; + nand_flash -> lx_nand_flash_backup_metadata_block_number_next = LX_NAND_BLOCK_UNMAPPED; + + /* Initialize the block status buffer. */ + LX_MEMSET(nand_flash -> lx_nand_flash_block_status_table, 0xFF, nand_flash -> lx_nand_flash_block_status_table_size); + + /* Loop through the blocks to check for bad blocks and determine the minimum and maximum erase count for each good block. */ + for (block = 0; block < nand_flash -> lx_nand_flash_total_blocks; block++) + { + + /* First, check to make sure this block is good. */ + status = _lx_nand_flash_driver_block_status_get(nand_flash, block, &block_status); + + /* Check for an error from flash driver. */ + if (status) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, block, 0); + + /* Return an error. */ + return(LX_ERROR); + } + + /* Is this block bad? */ + if (block_status != LX_NAND_GOOD_BLOCK) + { + + /* Yes, this block is bad. */ + + /* Increment the number of bad blocks. */ + nand_flash -> lx_nand_flash_bad_blocks++; + + /* Save the block status. */ + nand_flash -> lx_nand_flash_block_status_table[block] = LX_NAND_BLOCK_STATUS_BAD; + + /* Continue to the next block. */ + continue; + } + + /* Erase the block. */ + status = _lx_nand_flash_driver_block_erase(nand_flash, block, 0); + + /* Check for an error from flash driver. */ + if (status) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, block, 0); + + /* Attempt to mark this block as bad. */ + status = _lx_nand_flash_driver_block_status_set(nand_flash, block, LX_NAND_BAD_BLOCK); + + /* Check for error in setting the block status. */ + if (status) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, block, 0); + } + + /* Increment the bad block count. */ + nand_flash -> lx_nand_flash_bad_blocks++; + + /* Save the block status. */ + nand_flash -> lx_nand_flash_block_status_table[block] = LX_NAND_BLOCK_STATUS_BAD; + } + else + { + + /* Allocate blocks for metadata. */ + if (nand_flash -> lx_nand_flash_metadata_block_number == LX_NAND_BLOCK_UNMAPPED) + { + nand_flash -> lx_nand_flash_metadata_block_number = block; + nand_flash -> lx_nand_flash_metadata_block_number_current = block; + } + else if (nand_flash -> lx_nand_flash_backup_metadata_block_number == LX_NAND_BLOCK_UNMAPPED) + { + nand_flash -> lx_nand_flash_backup_metadata_block_number = block; + nand_flash -> lx_nand_flash_backup_metadata_block_number_current = block; + } + else if (nand_flash -> lx_nand_flash_metadata_block_number_next == LX_NAND_BLOCK_UNMAPPED) + { + nand_flash -> lx_nand_flash_metadata_block_number_next = block; + } + else if (nand_flash -> lx_nand_flash_backup_metadata_block_number_next == LX_NAND_BLOCK_UNMAPPED) + { + nand_flash -> lx_nand_flash_backup_metadata_block_number_next = block; + } + } + } + + /* There should be enough blocks for metadata. */ + if (nand_flash -> lx_nand_flash_backup_metadata_block_number_next == LX_NAND_BLOCK_UNMAPPED) + { + return (LX_NO_BLOCKS); + } + + /* Save the block status for metadata. */ + nand_flash -> lx_nand_flash_block_status_table[nand_flash -> lx_nand_flash_backup_metadata_block_number_next] = LX_NAND_BLOCK_STATUS_ALLOCATED; + nand_flash -> lx_nand_flash_block_status_table[nand_flash -> lx_nand_flash_metadata_block_number_next] = LX_NAND_BLOCK_STATUS_ALLOCATED; + nand_flash -> lx_nand_flash_block_status_table[nand_flash -> lx_nand_flash_backup_metadata_block_number] = (USHORT)nand_flash -> lx_nand_flash_backup_metadata_block_number_next; + nand_flash -> lx_nand_flash_block_status_table[nand_flash -> lx_nand_flash_metadata_block_number] = (USHORT)nand_flash -> lx_nand_flash_metadata_block_number_next; + + /* Initialize the mapping table. */ + LX_MEMSET(nand_flash -> lx_nand_flash_block_mapping_table, 0xFF, nand_flash -> lx_nand_flash_block_mapping_table_size); + + /* Build initial metadata. */ + status = _lx_nand_flash_metadata_build(nand_flash); + if (status != LX_SUCCESS) + { + /* Return error status. */ + return(status); + } + + /* Get buffer for page data. */ + page_buffer_ptr = nand_flash -> lx_nand_flash_page_buffer; + + /* Initialize the page buffer. */ + LX_MEMSET(page_buffer_ptr, 0xFF, nand_flash -> lx_nand_flash_bytes_per_page); + + /* Set the next block numbers. */ + LX_UTILITY_LONG_SET(&page_buffer_ptr[LX_NAND_BLOCK_LINK_MAIN_METADATA_OFFSET], nand_flash -> lx_nand_flash_metadata_block_number_next); + LX_UTILITY_LONG_SET(&page_buffer_ptr[LX_NAND_BLOCK_LINK_BACKUP_METADATA_OFFSET], nand_flash -> lx_nand_flash_backup_metadata_block_number_next); + + /* Save the next block numbers to metadata block. */ + status = _lx_nand_flash_metadata_write(nand_flash, page_buffer_ptr, LX_NAND_PAGE_TYPE_BLOCK_LINK); + + if (status != LX_SUCCESS) + { + /* Return error status. */ + return(status); + } + + /* Return a successful completion. */ + return(LX_SUCCESS); +} + diff --git a/common/src/lx_nand_flash_free_block_list_add.c b/common/src/lx_nand_flash_free_block_list_add.c new file mode 100644 index 0000000..99b0b3c --- /dev/null +++ b/common/src/lx_nand_flash_free_block_list_add.c @@ -0,0 +1,121 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** LevelX Component */ +/** */ +/** NAND Flash */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define LX_SOURCE_CODE + + +/* Disable ThreadX error checking. */ + +#ifndef LX_DISABLE_ERROR_CHECKING +#define LX_DISABLE_ERROR_CHECKING +#endif + + +/* Include necessary system files. */ + +#include "lx_api.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _lx_nand_flash_free_block_list_add PORTABLE C */ +/* 6.x */ +/* AUTHOR */ +/* */ +/* Xiuwen Cai, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds a block to free block list. */ +/* */ +/* INPUT */ +/* */ +/* nand_flash NAND flash instance */ +/* block Block number */ +/* */ +/* OUTPUT */ +/* */ +/* return status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Internal LevelX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* xx-xx-xxxx Xiuwen Cai Initial Version 6.x */ +/* */ +/**************************************************************************/ +UINT _lx_nand_flash_free_block_list_add(LX_NAND_FLASH* nand_flash, ULONG block) +{ + +ULONG insert_position; +INT search_position; +UCHAR new_block_erase_count; + + + /* Get insert position for the free block list. */ + insert_position = nand_flash -> lx_nand_flash_free_block_list_tail; + + /* Check if the list if full. */ + if (insert_position > nand_flash -> lx_nand_flash_mapped_block_list_head) + { + + /* Return an error. */ + return(LX_ERROR); + } + + /* Get the erase count. */ + new_block_erase_count = nand_flash -> lx_nand_flash_erase_count_table[block]; + + /* Add one block to the free list. */ + nand_flash -> lx_nand_flash_free_block_list_tail++; + + /* Initialize the search pointer. */ + search_position = (INT)insert_position - 1; + + /* Loop to search the insert position by block erase count. */ + while ((search_position >= 0) && + (nand_flash -> lx_nand_flash_erase_count_table[nand_flash -> lx_nand_flash_block_list[search_position]] < new_block_erase_count)) + { + + /* Move the item in the list. */ + nand_flash -> lx_nand_flash_block_list[insert_position] = nand_flash -> lx_nand_flash_block_list[search_position]; + search_position--; + insert_position--; + } + + /* Insert the new block to the list. */ + nand_flash -> lx_nand_flash_block_list[insert_position] = (USHORT)block; + + /* Return successful completion. */ + return(LX_SUCCESS); +} + diff --git a/common/src/lx_nand_flash_logical_sector_find.c b/common/src/lx_nand_flash_logical_sector_find.c deleted file mode 100644 index c60323b..0000000 --- a/common/src/lx_nand_flash_logical_sector_find.c +++ /dev/null @@ -1,841 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** LevelX Component */ -/** */ -/** NAND Flash */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -#define LX_SOURCE_CODE - - -/* Disable ThreadX error checking. */ - -#ifndef LX_DISABLE_ERROR_CHECKING -#define LX_DISABLE_ERROR_CHECKING -#endif - - -/* Include necessary system files. */ - -#include "lx_api.h" - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _lx_nand_flash_logical_sector_find PORTABLE C */ -/* 6.1.7 */ -/* AUTHOR */ -/* */ -/* William E. Lamie, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function attempts to find the specified logical sector in */ -/* the NAND flash. */ -/* */ -/* INPUT */ -/* */ -/* nand_flash NAND flash instance */ -/* logical_sector Logical sector number */ -/* superceded_check Check for page being */ -/* superceded (can happen if */ -/* on interruptions of page */ -/* write) */ -/* block Destination for block */ -/* page Destination for page */ -/* */ -/* OUTPUT */ -/* */ -/* return status */ -/* */ -/* CALLS */ -/* */ -/* _lx_nand_flash_driver_block_status_get */ -/* Driver block status */ -/* _lx_nand_flash_driver_extra_bytes_get Driver get extra bytes */ -/* _lx_nand_flash_driver_extra_bytes_set NAND flash set extra bytes */ -/* _lx_nand_flash_driver_read Driver page read */ -/* _lx_nand_flash_system_error Internal system error handler */ -/* */ -/* CALLED BY */ -/* */ -/* Internal LevelX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 William E. Lamie Initial Version 6.0 */ -/* 09-30-2020 William E. Lamie Modified comment(s), */ -/* resulting in version 6.1 */ -/* 06-02-2021 Bhupendra Naphade Modified comment(s), */ -/* resulting in version 6.1.7 */ -/* */ -/**************************************************************************/ -UINT _lx_nand_flash_logical_sector_find(LX_NAND_FLASH *nand_flash, ULONG logical_sector, ULONG superceded_check, ULONG *block, ULONG *page) -{ - -LX_NAND_PAGE_EXTRA_INFO extra_info; -UCHAR block_status; -ULONG *block_word_ptr; -ULONG valid_pages; -ULONG mapped_pages; -ULONG total_blocks; -ULONG total_pages; -ULONG i, j; -ULONG search_start; -ULONG max_mapped_sector; -#ifndef LX_NAND_FLASH_DIRECT_MAPPING_CACHE -LX_NAND_SECTOR_MAPPING_CACHE_ENTRY *sector_mapping_cache_entry_ptr = LX_NULL; -LX_NAND_SECTOR_MAPPING_CACHE_ENTRY temp_sector_mapping_cache_entry; -#endif -UINT status; - - - /* Initialize the return parameters. */ - *block = (ULONG) 0; - *page = (ULONG) 0; - - /* Determine if there are any mapped pages. */ - if (nand_flash -> lx_nand_flash_mapped_pages == 0) - { - - /* No mapped pages so nothing can be found!. */ - return(LX_SECTOR_NOT_FOUND); - } - - /* Determine if this logical sector is greater than what has previously been mapped. */ - if (logical_sector > nand_flash -> lx_nand_flash_max_mapped_sector) - { - - /* Since this logical sector request is greater than what has been mapped previously, - there is no point in searching any further. */ - - /* Return sector not found status. */ - return(LX_SECTOR_NOT_FOUND); - } - - /* Determine if the sector mapping cache is enabled. */ - if (nand_flash -> lx_nand_flash_sector_mapping_cache_enabled) - { - -#ifndef LX_NAND_FLASH_DIRECT_MAPPING_CACHE - - /* Calculate the starting index of the sector cache for this sector entry. */ - i = (logical_sector & LX_NAND_SECTOR_MAPPING_CACHE_HASH_MASK) * LX_NAND_SECTOR_MAPPING_CACHE_DEPTH; - - /* Build a pointer to the cache entry. */ - sector_mapping_cache_entry_ptr = &nand_flash -> lx_nand_flash_sector_mapping_cache[i]; - - /* Determine if the sector is in the sector mapping cache - assuming the depth of the sector - mapping cache is LX_NAND_SECTOR_MAPPING_CACHE_DEPTH entries. */ - if ((sector_mapping_cache_entry_ptr -> lx_nand_sector_mapping_cache_logical_sector) == (logical_sector | LX_NAND_SECTOR_MAPPING_CACHE_ENTRY_VALID)) - { - - /* Increment the sector mapping cache hit counter. */ - nand_flash -> lx_nand_flash_diagnostic_sector_mapping_cache_hits++; - - /* Yes, return the cached values associated with the sector. */ - *block = (ULONG) sector_mapping_cache_entry_ptr -> lx_nand_sector_mapping_cache_block; - *page = (ULONG) sector_mapping_cache_entry_ptr -> lx_nand_sector_mapping_cache_page; - - /* Don't move anything since we found the entry at the top. */ - - /* Return a successful status. */ - return(LX_SUCCESS); - } - else if (((sector_mapping_cache_entry_ptr + 1) -> lx_nand_sector_mapping_cache_logical_sector) == (logical_sector | LX_NAND_SECTOR_MAPPING_CACHE_ENTRY_VALID)) - { - - /* Increment the sector mapping cache hit counter. */ - nand_flash -> lx_nand_flash_diagnostic_sector_mapping_cache_hits++; - - /* Yes, return the cached values associated with the sector. */ - *block = (ULONG) (sector_mapping_cache_entry_ptr + 1) -> lx_nand_sector_mapping_cache_block; - *page = (ULONG) (sector_mapping_cache_entry_ptr + 1) -> lx_nand_sector_mapping_cache_page; - - /* Just swap the first and second entry. */ - temp_sector_mapping_cache_entry = *(sector_mapping_cache_entry_ptr); - *(sector_mapping_cache_entry_ptr) = *(sector_mapping_cache_entry_ptr + 1); - *(sector_mapping_cache_entry_ptr + 1) = temp_sector_mapping_cache_entry; - - /* Return a successful status. */ - return(LX_SUCCESS); - } - else if (((sector_mapping_cache_entry_ptr + 2) -> lx_nand_sector_mapping_cache_logical_sector) == (logical_sector | LX_NAND_SECTOR_MAPPING_CACHE_ENTRY_VALID)) - { - - /* Increment the sector mapping cache hit counter. */ - nand_flash -> lx_nand_flash_diagnostic_sector_mapping_cache_hits++; - - /* Yes, return the cached value. */ - *block = (ULONG) (sector_mapping_cache_entry_ptr + 2) -> lx_nand_sector_mapping_cache_block; - *page = (ULONG) (sector_mapping_cache_entry_ptr + 2) -> lx_nand_sector_mapping_cache_page; - - /* Move the third entry to the top and the first two entries down. */ - temp_sector_mapping_cache_entry = *(sector_mapping_cache_entry_ptr); - *(sector_mapping_cache_entry_ptr) = *(sector_mapping_cache_entry_ptr + 2); - *(sector_mapping_cache_entry_ptr + 2) = *(sector_mapping_cache_entry_ptr + 1); - *(sector_mapping_cache_entry_ptr + 1) = temp_sector_mapping_cache_entry; - - /* Return a successful status. */ - return(LX_SUCCESS); - } - else if (((sector_mapping_cache_entry_ptr + 3) -> lx_nand_sector_mapping_cache_logical_sector) == (logical_sector | LX_NAND_SECTOR_MAPPING_CACHE_ENTRY_VALID)) - { - - /* Increment the sector mapping cache hit counter. */ - nand_flash -> lx_nand_flash_diagnostic_sector_mapping_cache_hits++; - - /* Yes, return the cached value. */ - *block = (ULONG) (sector_mapping_cache_entry_ptr + 3) -> lx_nand_sector_mapping_cache_block; - *page = (ULONG) (sector_mapping_cache_entry_ptr + 3) -> lx_nand_sector_mapping_cache_page; - - /* Move the last entry to the top and the first three entries down. */ - temp_sector_mapping_cache_entry = *(sector_mapping_cache_entry_ptr); - *(sector_mapping_cache_entry_ptr) = *(sector_mapping_cache_entry_ptr + 3); - *(sector_mapping_cache_entry_ptr + 3) = *(sector_mapping_cache_entry_ptr + 2); - *(sector_mapping_cache_entry_ptr + 2) = *(sector_mapping_cache_entry_ptr + 1); - *(sector_mapping_cache_entry_ptr + 1) = temp_sector_mapping_cache_entry; - - /* Return a successful status. */ - return(LX_SUCCESS); - } - - /* If we get here, we have a cache miss so increment the counter before we fall through to the search loop. */ - nand_flash -> lx_nand_flash_diagnostic_sector_mapping_cache_misses++; -#else - - /* Direct mapping cache is defined. */ - - /* See if we are still opening the flash. */ - if (nand_flash -> lx_nand_flash_state == LX_NAND_FLASH_OPENED) - { - - /* Flash instance is opened. */ - - /* Determine if this logical sector fits in the logical sector direct cache mapping. */ - if (logical_sector < LX_NAND_SECTOR_MAPPING_CACHE_SIZE) - { - - /* Yes, invalidate the logical sector cache. */ - if ((nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_block == 0) && - (nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_page == 0)) - { - - /* Entry is not mapped. */ - - /* No, return sector not found status. */ - return(LX_SECTOR_NOT_FOUND); - } - else - { - - /* Sector is mapped, return the block and page of the mapping. */ - *block = nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_block; - *page = nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_page; - - /* Return a successful status. */ - return(LX_SUCCESS); - } - } - } - else - { - - /* If we get here, we have a cache miss so increment the counter before we fall through to the search loop. */ - nand_flash -> lx_nand_flash_diagnostic_sector_mapping_cache_misses++; - } -#endif - } - - /* Clear the maximum mapped sector. */ - max_mapped_sector = 0; - - /* Setup the total number of mapped pages. */ - mapped_pages = nand_flash -> lx_nand_flash_mapped_pages; - - /* Setup pointer to internal buffer. */ - block_word_ptr = nand_flash -> lx_nand_flash_page_buffer; - - /* Start searching from the last found block. */ - i = nand_flash -> lx_nand_flash_found_block_search; - - /* Setup the starting page to look at. */ - j = nand_flash -> lx_nand_flash_found_page_search; - - /* Pickup the total number of blocks. */ - total_blocks = nand_flash -> lx_nand_flash_total_blocks; - - /* Loop through the blocks to attempt to find the mapped logical sector. */ - while (total_blocks--) - { - - /* First, check to make sure this block is good. */ - status = _lx_nand_flash_driver_block_status_get(nand_flash, i, &block_status); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, i, 0); - - /* Return the error. */ - return(status); - } - - /* Is this block bad? */ - if (block_status != LX_NAND_GOOD_BLOCK) - { - - /* Yes, this block is bad. */ - - /* Move to the next block. */ - i++; - - /* Check for wrap condition. */ - if (i >= nand_flash -> lx_nand_flash_total_blocks) - { - - /* Wrap to the first block. */ - i = 0; - } - - /* Start looking at the first page of the next block. */ - j = 1; - - /* Continue to the next block. */ - continue; - } - - /* Read the extra bytes of page 0. This will tell us if the page has any valid mappings. */ - status = _lx_nand_flash_driver_extra_bytes_get(nand_flash, i, 0, (UCHAR *) &extra_info, sizeof(extra_info)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, i, 0); - - /* Return the error... no point in continuing. */ - return(status); - } - - /* Determine if there are any valid mappings. */ - if (((extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_BLOCK_VALID) == 0) || - ((extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_BLOCK_EMPTY) != 0)) - { - - /* Yes, this block is either no longer valid or is empty, i.e., no mappings. */ - - /* Move to the next block. */ - i++; - - /* Check for wrap condition. */ - if (i >= nand_flash -> lx_nand_flash_total_blocks) - { - - /* Wrap to the first block. */ - i = 0; - } - - /* Reset to the first page of the next block. */ - j = 1; - - /* Continue to the next block. */ - continue; - } - - /* Now read page 0 of the block, which has the erase count in the first 4 bytes. */ - status = _lx_nand_flash_driver_read(nand_flash, i, 0, block_word_ptr, (nand_flash -> lx_nand_flash_pages_per_block + 1)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, i, 0); - - /* Determine if the error is fatal. */ - if (status != LX_NAND_ERROR_CORRECTED) - { - - /* Return the error. */ - return(status); - } - } - - /* Determine if we have a valid logical sector mapping list. */ - if ((block_word_ptr[1] != LX_NAND_PAGE_FREE) && - (block_word_ptr[nand_flash -> lx_nand_flash_pages_per_block] == LX_NAND_PAGE_LIST_VALID)) - { - - /* Yes, we have a valid logical sector mapping list in page 0. */ - - /* Clear the valid entries counter. */ - valid_pages = 0; - - /* Setup the total number of pages, less the metadata page. */ - total_pages = nand_flash -> lx_nand_flash_pages_per_block - 1; - - /* Now search through the sector list to find a match. */ - while (total_pages--) - { - - /* Is this entry valid? */ - if ((block_word_ptr[j] & (LX_NAND_PAGE_VALID | LX_NAND_PAGE_MAPPING_NOT_VALID)) == LX_NAND_PAGE_VALID) - { - - /* Increment the valid entries counter. */ - valid_pages++; - - /* Determine if this is a new maximum logical sector. */ - if ((block_word_ptr[j] & LX_NAND_LOGICAL_SECTOR_MASK) > max_mapped_sector) - { - - /* Yes, a new maximum mapped sectors - remember it! */ - max_mapped_sector = (block_word_ptr[j] & LX_NAND_LOGICAL_SECTOR_MASK); - } - - /* Do we have a valid sector match? */ - if ((block_word_ptr[j] & LX_NAND_LOGICAL_SECTOR_MASK) == logical_sector) - { - - /* Read in the actual page entry to make sure this logical sector mapping is still valid. */ - status = _lx_nand_flash_driver_extra_bytes_get(nand_flash, i, j, (UCHAR *) &extra_info, sizeof(extra_info)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, i, j); - - /* Return the error. */ - return(status); - } - - /* Verify that the actual page still has a valid sector mapping. */ - if (((extra_info.lx_nand_page_extra_info_logical_sector & (LX_NAND_PAGE_VALID | LX_NAND_PAGE_MAPPING_NOT_VALID)) == LX_NAND_PAGE_VALID) && - ((extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_LOGICAL_SECTOR_MASK) == logical_sector)) - { - - /* Decrement the number of mapped pages to examine. */ - mapped_pages--; - - /* Determine if we care about the superceded bit. */ - if (superceded_check == LX_FALSE) - { - - /* Prepare the return information. */ - *block = i; - *page = j; - - /* Determine if the sector mapping cache is enabled. */ - if (nand_flash -> lx_nand_flash_sector_mapping_cache_enabled) - { - -#ifndef LX_NAND_FLASH_DIRECT_MAPPING_CACHE - - /* Yes, update the cache with the logical sector mapping. */ - - /* Move all the cache entries down so the oldest is at the bottom. */ - *(sector_mapping_cache_entry_ptr + 3) = *(sector_mapping_cache_entry_ptr + 2); - *(sector_mapping_cache_entry_ptr + 2) = *(sector_mapping_cache_entry_ptr + 1); - *(sector_mapping_cache_entry_ptr + 1) = *(sector_mapping_cache_entry_ptr); - - /* Setup the new sector information in the cache. */ - sector_mapping_cache_entry_ptr -> lx_nand_sector_mapping_cache_logical_sector = (logical_sector | LX_NAND_SECTOR_MAPPING_CACHE_ENTRY_VALID); - sector_mapping_cache_entry_ptr -> lx_nand_sector_mapping_cache_block = (USHORT) i; - sector_mapping_cache_entry_ptr -> lx_nand_sector_mapping_cache_page = (USHORT) j; -#else - - /* Determine if this logical sector fits in the logical sector cache mapping. */ - if (logical_sector < LX_NAND_SECTOR_MAPPING_CACHE_SIZE) - { - - /* Yes, store the logical sector to block/page mapping in the cache. */ - nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_block = (USHORT) i; - nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_page = (USHORT) j; - } -#endif - } - - /* Move to the next page. */ - j++; - - /* Determine if the page has wrapped around. */ - if (j >= nand_flash -> lx_nand_flash_pages_per_block) - { - - /* Yes, page wrapped. Move to page 1 of the next block. */ - j = 1; - } - - /* Remember the last found block and page for next search. */ - nand_flash -> lx_nand_flash_found_block_search = i; - nand_flash -> lx_nand_flash_found_page_search = j; - - /* Return success! */ - return(LX_SUCCESS); - } - - /* Check for the superceded bit being clear, which means the sector was superceded. */ - else if (extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_PAGE_SUPERCEDED) - { - - /* Prepare the return information. */ - *block = i; - *page = j; - - /* No need to update the cache here, since this condition only happens during initialization. */ - - /* Move to the next page. */ - j++; - - /* Determine if the page has wrapped around. */ - if (j >= nand_flash -> lx_nand_flash_pages_per_block) - { - - /* Yes, page wrapped. Move to page 1 of the next block. */ - j = 1; - } - - /* Remember the last found block and page for next search. */ - nand_flash -> lx_nand_flash_found_block_search = i; - nand_flash -> lx_nand_flash_found_page_search = j; - - /* Return success! */ - return(LX_SUCCESS); - } - } - else - { - - /* The entry is not really valid anymore, decrement the valid entries counter. */ - valid_pages--; - } - } - } - - /* Move to the next page. */ - j++; - - /* Check for wrap condition. */ - if (j >= nand_flash -> lx_nand_flash_pages_per_block) - { - - /* Yes, page has wrapped, reset to page 1. */ - j = 1; - } - } - - /* At this point we know that nothing matched in the mapping list. Now we need to check to see if there are any valid entries. */ - if (valid_pages) - { - - /* Reset the valid pages counter. */ - valid_pages = 0; - - /* Setup the total number of pages, less the metadata page. */ - total_pages = nand_flash -> lx_nand_flash_pages_per_block - 1; - - /* Now search through the sector list to find a match. */ - while (total_pages--) - { - - /* Is this entry valid? */ - if ((block_word_ptr[j] & (LX_NAND_PAGE_VALID | LX_NAND_PAGE_MAPPING_NOT_VALID)) == LX_NAND_PAGE_VALID) - { - - /* Read in the actual page entry to make sure this logical sector mapping is still valid. */ - status = _lx_nand_flash_driver_extra_bytes_get(nand_flash, i, j, (UCHAR *) &extra_info, sizeof(extra_info)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, i, j); - - /* Return the error. */ - return(status); - } - - /* Verify that the actual page still has a valid sector mapping. */ - if ((extra_info.lx_nand_page_extra_info_logical_sector & (LX_NAND_PAGE_VALID | LX_NAND_PAGE_MAPPING_NOT_VALID)) == LX_NAND_PAGE_VALID) - { - - /* Set the valid pages counter to 1 and break the loop. */ - valid_pages = 1; - - /* If one entry is valid, we can stop looking. */ - break; - } - } - - /* Move to the next page. */ - j++; - - /* Check for wrap condition. */ - if (j >= nand_flash -> lx_nand_flash_pages_per_block) - { - - /* Yes, page has wrapped, reset to page 1. */ - j = 1; - } - } - } - - /* Now, a final check for valid pages. */ - if (valid_pages == 0) - { - - /* There are no valid entries. We can now mark this block as not valid since there are no active - mappings. This will prevent us from examining it again during the search process. */ - extra_info.lx_nand_page_extra_info_logical_sector = 0; - status = _lx_nand_flash_driver_extra_bytes_set(nand_flash, i, 0, (UCHAR *) &extra_info, sizeof(extra_info)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, i, 0); - } - - /* Reset the search page to 1. */ - j = 1; - } - } - else - { - - /* No, we don't have a valid logical sector mapping list. */ - - /* Setup the total number of pages, less the metadata page. */ - total_pages = nand_flash -> lx_nand_flash_pages_per_block - 1; - - /* Remember the start of the search. */ - search_start = j; - - /* Now search through the sector list to find a match. */ - while (total_pages--) - { - - /* Read in the actual page entry to look for the logical sector mapping. */ - status = _lx_nand_flash_driver_extra_bytes_get(nand_flash, i, j, (UCHAR *) &extra_info, sizeof(extra_info)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, i, j); - - /* Return the error. */ - return(status); - } - - /* Is there a logical page mapping? */ - if (extra_info.lx_nand_page_extra_info_logical_sector == LX_NAND_PAGE_FREE) - { - - /* Since the mapping is done sequentially in the block, we know nothing - else exists after this point. */ - - /* Determine if the search started at the beginning of the block. */ - if (search_start == 1) - { - - /* Yes, we started at the beginning of the block. We are now done with this block. */ - break; - } - else - { - - /* Setup the new total to the search start. */ - total_pages = (search_start - 1); - - /* Clear search start. */ - search_start = 1; - - /* Start search over. */ - j = 1; - continue; - } - } - - /* Is this page mapping valid? */ - if ((extra_info.lx_nand_page_extra_info_logical_sector & (LX_NAND_PAGE_VALID | LX_NAND_PAGE_MAPPING_NOT_VALID)) == LX_NAND_PAGE_VALID) - { - - /* Yes, this page mapping is valid. */ - - /* Decrease the number of pages to examine. */ - mapped_pages--; - - - /* Determine if this is a new maximum logical sector. */ - if ((extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_LOGICAL_SECTOR_MASK) > max_mapped_sector) - { - - /* Yes, a new maximum mapped sectors - remember it! */ - max_mapped_sector = (extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_LOGICAL_SECTOR_MASK); - } - - /* Do we have a valid sector match? */ - if ((extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_LOGICAL_SECTOR_MASK) == logical_sector) - { - - /* Determine if we care about the superceded bit. */ - if (superceded_check == LX_FALSE) - { - - /* Prepare the return information. */ - *block = i; - *page = j; - - /* Determine if the sector mapping cache is enabled. */ - if (nand_flash -> lx_nand_flash_sector_mapping_cache_enabled) - { - - /* Yes, update the cache with the logical sector mapping. */ - -#ifndef LX_NAND_FLASH_DIRECT_MAPPING_CACHE - - /* Move all the cache entries down so the oldest is at the bottom. */ - *(sector_mapping_cache_entry_ptr + 3) = *(sector_mapping_cache_entry_ptr + 2); - *(sector_mapping_cache_entry_ptr + 2) = *(sector_mapping_cache_entry_ptr + 1); - *(sector_mapping_cache_entry_ptr + 1) = *(sector_mapping_cache_entry_ptr); - - /* Setup the new sector information in the cache. */ - sector_mapping_cache_entry_ptr -> lx_nand_sector_mapping_cache_logical_sector = (logical_sector | LX_NAND_SECTOR_MAPPING_CACHE_ENTRY_VALID); - sector_mapping_cache_entry_ptr -> lx_nand_sector_mapping_cache_block = (USHORT) i; - sector_mapping_cache_entry_ptr -> lx_nand_sector_mapping_cache_page = (USHORT) j; -#else - - /* Determine if this logical sector fits in the logical sector cache mapping. */ - if (logical_sector < LX_NAND_SECTOR_MAPPING_CACHE_SIZE) - { - - /* Yes, store the logical sector to block/page mapping in the cache. */ - nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_block = (USHORT) i; - nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_page = (USHORT) j; - } -#endif - } - - /* Move to the next page. */ - j++; - - /* Determine if the page has wrapped around. */ - if (j >= nand_flash -> lx_nand_flash_pages_per_block) - { - - /* Yes, page wrapped - move to page 1. */ - j = 1; - } - - /* Remember the last found block and page for next search. */ - nand_flash -> lx_nand_flash_found_block_search = i; - nand_flash -> lx_nand_flash_found_page_search = j; - - /* Return success! */ - return(LX_SUCCESS); - } - - /* Check for the superceded bit being clear, which means the sector was superceded. */ - else if (extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_PAGE_SUPERCEDED) - { - - /* Prepare the return information. */ - *block = i; - *page = j; - - /* No need to update the cache here, since this condition only happens during initialization. */ - - /* Move to the next page. */ - j++; - - /* Determine if the page has wrapped around. */ - if (j >= nand_flash -> lx_nand_flash_pages_per_block) - { - - /* Yes, page wrapped - move to page 1. */ - j = 1; - } - - /* Remember the last found block and page for next search. */ - nand_flash -> lx_nand_flash_found_block_search = i; - nand_flash -> lx_nand_flash_found_page_search = j; - - /* Return success! */ - return(LX_SUCCESS); - } - } - } - - /* Move to next page. */ - j++; - - /* Determine if we have a wrap-around condition. */ - if (j >= nand_flash -> lx_nand_flash_pages_per_block) - { - - /* Yes, page wrapped - move to page 1. */ - j = 1; - } - } - } - - /* Determine if there are any more mapped sectors. */ - if (mapped_pages == 0) - break; - - /* Move to the next block. */ - i++; - - /* Check for wrap condition. */ - if (i >= nand_flash -> lx_nand_flash_total_blocks) - { - - /* Wrap to the first block. */ - i = 0; - } - - /* Start at the first page in the next block. */ - j = 1; - } - - /* Determine if we should update the maximum mapped sector. */ - if (nand_flash -> lx_nand_flash_max_mapped_sector != 0xFFFFFFFF) - { - - /* Yes, update the maximum mapped sector. */ - nand_flash -> lx_nand_flash_max_mapped_sector = max_mapped_sector; - } - - /* Return sector not found status. */ - return(LX_SECTOR_NOT_FOUND); -} - diff --git a/common/src/lx_nand_flash_mapped_block_list_add.c b/common/src/lx_nand_flash_mapped_block_list_add.c new file mode 100644 index 0000000..e6ad1df --- /dev/null +++ b/common/src/lx_nand_flash_mapped_block_list_add.c @@ -0,0 +1,121 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** LevelX Component */ +/** */ +/** NAND Flash */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define LX_SOURCE_CODE + + +/* Disable ThreadX error checking. */ + +#ifndef LX_DISABLE_ERROR_CHECKING +#define LX_DISABLE_ERROR_CHECKING +#endif + + +/* Include necessary system files. */ + +#include "lx_api.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _lx_nand_flash_mapped_block_list_add PORTABLE C */ +/* 6.x */ +/* AUTHOR */ +/* */ +/* Xiuwen Cai, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds a block to mapped block list. */ +/* */ +/* INPUT */ +/* */ +/* nand_flash NAND flash instance */ +/* block_mapping_index Block mapping index */ +/* */ +/* OUTPUT */ +/* */ +/* return status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Internal LevelX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* xx-xx-xxxx Xiuwen Cai Initial Version 6.x */ +/* */ +/**************************************************************************/ +UINT _lx_nand_flash_mapped_block_list_add(LX_NAND_FLASH* nand_flash, ULONG block_mapping_index) +{ + +ULONG insert_position; +ULONG search_position; +UCHAR new_block_erase_count; + + + /* Get insert position for the mapped block list. */ + insert_position = nand_flash -> lx_nand_flash_mapped_block_list_head; + + /* Check if the list if full. */ + if (insert_position < nand_flash -> lx_nand_flash_free_block_list_tail) + { + + /* Return an error. */ + return(LX_ERROR); + } + + /* Get the erase count. */ + new_block_erase_count = nand_flash -> lx_nand_flash_erase_count_table[nand_flash -> lx_nand_flash_block_mapping_table[block_mapping_index]]; + + /* Add one block to the free list. */ + nand_flash -> lx_nand_flash_mapped_block_list_head--; + + /* Initialize the search pointer. */ + search_position = insert_position + 1; + + /* Loop to search the insert position. */ + while ((search_position < nand_flash -> lx_nand_flash_block_list_size) && + (nand_flash -> lx_nand_flash_erase_count_table[nand_flash -> lx_nand_flash_block_mapping_table[nand_flash -> lx_nand_flash_block_list[search_position]]] < new_block_erase_count)) + { + + /* Move the item in the list. */ + nand_flash -> lx_nand_flash_block_list[insert_position] = nand_flash -> lx_nand_flash_block_list[search_position]; + search_position++; + insert_position++; + } + + /* Insert the new block to the list. */ + nand_flash -> lx_nand_flash_block_list[insert_position] = (USHORT)block_mapping_index; + + /* Return successful completion. */ + return(LX_SUCCESS); +} + diff --git a/common/src/lx_nand_flash_mapped_block_list_get.c b/common/src/lx_nand_flash_mapped_block_list_get.c new file mode 100644 index 0000000..0f45ce9 --- /dev/null +++ b/common/src/lx_nand_flash_mapped_block_list_get.c @@ -0,0 +1,98 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** LevelX Component */ +/** */ +/** NAND Flash */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define LX_SOURCE_CODE + + +/* Disable ThreadX error checking. */ + +#ifndef LX_DISABLE_ERROR_CHECKING +#define LX_DISABLE_ERROR_CHECKING +#endif + + +/* Include necessary system files. */ + +#include "lx_api.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _lx_nand_flash_mapped_block_list_get PORTABLE C */ +/* 6.x */ +/* AUTHOR */ +/* */ +/* Xiuwen Cai, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function gets a block from mapped block list and removes it */ +/* from the list. */ +/* */ +/* INPUT */ +/* */ +/* nand_flash NAND flash instance */ +/* block_mapping_index Pointer to block mapping index*/ +/* */ +/* OUTPUT */ +/* */ +/* return status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Internal LevelX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* xx-xx-xxxx Xiuwen Cai Initial Version 6.x */ +/* */ +/**************************************************************************/ +UINT _lx_nand_flash_mapped_block_list_get(LX_NAND_FLASH* nand_flash, ULONG *block_mapping_index) +{ + + + /* Check if the mapped block list is empty. */ + if (nand_flash -> lx_nand_flash_mapped_block_list_head == nand_flash -> lx_nand_flash_block_list_size - 1) + { + + /* Empty list, return error. */ + return(LX_NO_BLOCKS); + } + + /* Remove one block from the list. */ + nand_flash -> lx_nand_flash_mapped_block_list_head++; + + /* Return the block number. */ + *block_mapping_index = nand_flash -> lx_nand_flash_block_list[nand_flash -> lx_nand_flash_mapped_block_list_head]; + + /* Return successful completion. */ + return(LX_SUCCESS); +} + diff --git a/common/src/lx_nand_flash_mapped_block_list_remove.c b/common/src/lx_nand_flash_mapped_block_list_remove.c new file mode 100644 index 0000000..2bdbbf9 --- /dev/null +++ b/common/src/lx_nand_flash_mapped_block_list_remove.c @@ -0,0 +1,127 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** LevelX Component */ +/** */ +/** NAND Flash */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define LX_SOURCE_CODE + + +/* Disable ThreadX error checking. */ + +#ifndef LX_DISABLE_ERROR_CHECKING +#define LX_DISABLE_ERROR_CHECKING +#endif + + +/* Include necessary system files. */ + +#include "lx_api.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _lx_nand_flash_mapped_block_list_remove PORTABLE C */ +/* 6.x */ +/* AUTHOR */ +/* */ +/* Xiuwen Cai, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function removes mapped block from list. */ +/* */ +/* INPUT */ +/* */ +/* nand_flash NAND flash instance */ +/* block_mapping_index Block mapping index */ +/* */ +/* OUTPUT */ +/* */ +/* return status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Internal LevelX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* xx-xx-xxxx Xiuwen Cai Initial Version 6.x */ +/* */ +/**************************************************************************/ +UINT _lx_nand_flash_mapped_block_list_remove(LX_NAND_FLASH* nand_flash, ULONG block_mapping_index) +{ + +ULONG search_position; + + + /* Initialize the search pointer. */ + search_position = nand_flash -> lx_nand_flash_mapped_block_list_head + 1; + + /* Loop to search the block in the list. */ + while (search_position < nand_flash -> lx_nand_flash_block_list_size) + { + + /* Check if there is a match in the list. */ + if (nand_flash -> lx_nand_flash_block_list[search_position] == block_mapping_index) + { + + /* Get out of the loop. */ + break; + } + + /* Move to next position. */ + search_position++; + } + + /* Check if the block is found. */ + if (search_position < nand_flash -> lx_nand_flash_block_list_size) + { + + /* Remove one item from the list. */ + nand_flash -> lx_nand_flash_mapped_block_list_head++; + + /* Loop to move items in the list. */ + while (search_position > nand_flash -> lx_nand_flash_mapped_block_list_head) + { + + /* Move the item in the list. */ + nand_flash -> lx_nand_flash_block_list[search_position] = nand_flash -> lx_nand_flash_block_list[search_position - 1]; + search_position--; + } + } + else + { + + /* Return error. */ + return(LX_NO_BLOCKS); + } + + /* Return successful completion. */ + return(LX_SUCCESS); +} + diff --git a/common/src/lx_nand_flash_memory_initialize.c b/common/src/lx_nand_flash_memory_initialize.c new file mode 100644 index 0000000..bc20cb0 --- /dev/null +++ b/common/src/lx_nand_flash_memory_initialize.c @@ -0,0 +1,207 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** LevelX Component */ +/** */ +/** NAND Flash */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define LX_SOURCE_CODE + + +/* Disable ThreadX error checking. */ + +#ifndef LX_DISABLE_ERROR_CHECKING +#define LX_DISABLE_ERROR_CHECKING +#endif + + +/* Include necessary system files. */ + +#include "lx_api.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _lx_nand_flash_memory_initialize PORTABLE C */ +/* 6.x */ +/* AUTHOR */ +/* */ +/* Xiuwen Cai, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function imitialize memory buffer for NAND flash instance. */ +/* */ +/* INPUT */ +/* */ +/* nand_flash NAND flash instance */ +/* memory_ptr Pointer to memory used by the */ +/* LevelX for this NAND. */ +/* memory_size Size of memory */ +/* */ +/* OUTPUT */ +/* */ +/* return status */ +/* */ +/* CALLS */ +/* */ +/* LX_MEMSET Initialize memory */ +/* */ +/* CALLED BY */ +/* */ +/* Internal LevelX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* xx-xx-xxxx Xiuwen Cai Initial Version 6.x */ +/* */ +/**************************************************************************/ +UINT _lx_nand_flash_memory_initialize(LX_NAND_FLASH *nand_flash, ULONG* memory_ptr, UINT memory_size) +{ + +UINT memory_offset; +UINT buffer_size; + + + /* Clear the memory buffer. */ + LX_MEMSET(memory_ptr, 0, memory_size); + + /* Reset the memory offset. */ + memory_offset = 0; + + /* Set memory size for block mapping table. */ + buffer_size = nand_flash -> lx_nand_flash_total_blocks * sizeof(*nand_flash -> lx_nand_flash_block_mapping_table); + + /* Make sure the size is at least one page size. */ + if (buffer_size < nand_flash -> lx_nand_flash_bytes_per_page) + { + buffer_size = nand_flash -> lx_nand_flash_bytes_per_page; + } + + /* Assign memory for block mapping table. */ + nand_flash -> lx_nand_flash_block_mapping_table = (USHORT*)(((UCHAR*)memory_ptr) + memory_offset); + + /* Update block mapping table size. */ + nand_flash -> lx_nand_flash_block_mapping_table_size = buffer_size; + + /* Update memory offset. */ + memory_offset += buffer_size; + + /* Check if there is enough memory. */ + if (memory_offset > memory_size) + { + + /* No enough memory, return error. */ + return(LX_NO_MEMORY); + } + + /* Set memory size for erase count table. */ + buffer_size = nand_flash -> lx_nand_flash_total_blocks * sizeof(*nand_flash -> lx_nand_flash_erase_count_table); + + /* Make sure the size is at least one page size. */ + if (buffer_size < nand_flash -> lx_nand_flash_bytes_per_page) + { + buffer_size = nand_flash -> lx_nand_flash_bytes_per_page; + } + + /* Assign memory for erase count table. */ + nand_flash -> lx_nand_flash_erase_count_table = (UCHAR*)(((UCHAR*)memory_ptr) + memory_offset); + + /* Update memory offset. */ + memory_offset += buffer_size; + + /* Update erase count table size. */ + nand_flash -> lx_nand_flash_erase_count_table_size = buffer_size; + + /* Check if there is enough memory. */ + if (memory_offset > memory_size) + { + + /* No enough memory, return error. */ + return(LX_NO_MEMORY); + } + + /* Assign memory for block list. */ + nand_flash -> lx_nand_flash_block_list = (USHORT*)(((UCHAR*)memory_ptr) + memory_offset); + + /* Update memory offset. */ + memory_offset += nand_flash -> lx_nand_flash_total_blocks * sizeof(*nand_flash -> lx_nand_flash_block_list); + + /* Check if there is enough memory. */ + if (memory_offset > memory_size) + { + + /* No enough memory, return error. */ + return(LX_NO_MEMORY); + } + + /* Update block list size. */ + nand_flash -> lx_nand_flash_block_list_size = nand_flash -> lx_nand_flash_total_blocks; + + /* Initialize block list. */ + nand_flash -> lx_nand_flash_free_block_list_tail = 0; + nand_flash -> lx_nand_flash_mapped_block_list_head = nand_flash -> lx_nand_flash_block_list_size - 1; + + /* Set memory size for block status table. */ + buffer_size = nand_flash -> lx_nand_flash_total_blocks * sizeof(*nand_flash -> lx_nand_flash_block_status_table); + + /* Make sure the size is at least one page size. */ + if (buffer_size < nand_flash -> lx_nand_flash_bytes_per_page) + { + buffer_size = nand_flash -> lx_nand_flash_bytes_per_page; + } + + /* Assign memory for block status table. */ + nand_flash -> lx_nand_flash_block_status_table = (USHORT*)(((UCHAR*)memory_ptr) + memory_offset); + + /* Update memory offset. */ + memory_offset += buffer_size; + + /* Update block status table size. */ + nand_flash -> lx_nand_flash_block_status_table_size = buffer_size; + + /* Check if there is enough memory. */ + if (memory_offset > memory_size) + { + + /* No enough memory, return error. */ + return(LX_NO_MEMORY); + } + + /* Assign memory for page buffer. */ + nand_flash -> lx_nand_flash_page_buffer = ((UCHAR*)memory_ptr) + memory_offset; + + /* Update page buffer size. */ + nand_flash -> lx_nand_flash_page_buffer_size = memory_size - memory_offset; + + /* Check if there is enough memory. */ + if (nand_flash -> lx_nand_flash_page_buffer_size < (nand_flash -> lx_nand_flash_bytes_per_page + nand_flash -> lx_nand_flash_spare_total_length) * 2) + { + + /* No enough memory, return error. */ + return(LX_NO_MEMORY); + } + + /* Return a successful completion. */ + return(LX_SUCCESS); +} + diff --git a/common/src/lx_nand_flash_metadata_allocate.c b/common/src/lx_nand_flash_metadata_allocate.c new file mode 100644 index 0000000..4ac025a --- /dev/null +++ b/common/src/lx_nand_flash_metadata_allocate.c @@ -0,0 +1,374 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** LevelX Component */ +/** */ +/** NAND Flash */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define LX_SOURCE_CODE + + +/* Disable ThreadX error checking. */ + +#ifndef LX_DISABLE_ERROR_CHECKING +#define LX_DISABLE_ERROR_CHECKING +#endif + + +/* Include necessary system files. */ + +#include "lx_api.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _lx_nand_flash_metadata_allocate PORTABLE C */ +/* 6.x */ +/* AUTHOR */ +/* */ +/* Xiuwen Cai, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function allocates new blocks for metadata if current metadata */ +/* block is full. This function also frees metadata blocks if the chain*/ +/* is too long. */ +/* */ +/* INPUT */ +/* */ +/* nand_flash NAND flash instance */ +/* */ +/* OUTPUT */ +/* */ +/* return status */ +/* */ +/* CALLS */ +/* */ +/* _lx_nand_flash_metadata_build Build metadata */ +/* _lx_nand_flash_driver_block_erase Erase block */ +/* _lx_nand_flash_block_data_move Move block data */ +/* _lx_nand_flash_free_block_list_add Add free block list */ +/* _lx_nand_flash_block_allocate Allocate block */ +/* _lx_nand_flash_block_status_set Set block status */ +/* _lx_nand_flash_metadata_write Write metadata */ +/* _lx_nand_flash_system_error Internal system error handler */ +/* */ +/* CALLED BY */ +/* */ +/* Internal LevelX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* xx-xx-xxxx Xiuwen Cai Initial Version 6.x */ +/* */ +/**************************************************************************/ +UINT _lx_nand_flash_metadata_allocate(LX_NAND_FLASH *nand_flash) +{ + +ULONG block; +ULONG page; +UINT status; +UCHAR *page_buffer_ptr; +UINT j; +UCHAR min_erase_count; + + + /* Get current page for metadata block. */ + page = nand_flash -> lx_nand_flash_metadata_block_current_page; + + /* Check if new metadata block is required. */ + if (page < nand_flash -> lx_nand_flash_pages_per_block) + { + + /* No new block is required. Just return success. */ + return(LX_SUCCESS); + } + + /* Advance to next metadata block. */ + nand_flash -> lx_nand_flash_metadata_block_number_current = nand_flash -> lx_nand_flash_metadata_block_number_next; + + /* Reset current page number. */ + nand_flash -> lx_nand_flash_metadata_block_current_page = 0; + + /* Advance to next backup metadata block. */ + nand_flash -> lx_nand_flash_backup_metadata_block_number_current = nand_flash -> lx_nand_flash_backup_metadata_block_number_next; + + /* Reset current page number for backup metadata block. */ + nand_flash -> lx_nand_flash_backup_metadata_block_current_page = 0; + + /* Check if number of allocated blocks reaches maximum. */ + if (nand_flash -> lx_nand_flash_metadata_block_count == LX_NAND_FLASH_MAX_METADATA_BLOCKS) + { + + /* Loop to mark metadata blocks as free. */ + for (j = 0; j < LX_NAND_FLASH_MAX_METADATA_BLOCKS - 1; j++) + { + + /* Free metadata block. */ + nand_flash -> lx_nand_flash_block_status_table[nand_flash -> lx_nand_flash_metadata_block[j]] = LX_NAND_BLOCK_STATUS_FREE; + + /* Free backup metadata block. */ + nand_flash -> lx_nand_flash_block_status_table[nand_flash -> lx_nand_flash_backup_metadata_block[j]] = LX_NAND_BLOCK_STATUS_FREE; + + /* Increase erase count. */ + nand_flash -> lx_nand_flash_erase_count_table[nand_flash -> lx_nand_flash_metadata_block[j]]++; + + /* Increase erase count for backup metadata block. */ + nand_flash -> lx_nand_flash_erase_count_table[nand_flash -> lx_nand_flash_backup_metadata_block[j]]++; + } + + /* Set new metadata block head. */ + nand_flash -> lx_nand_flash_metadata_block_number = nand_flash -> lx_nand_flash_metadata_block_number_current; + + /* Set new backup metadata block head. */ + nand_flash -> lx_nand_flash_backup_metadata_block_number = nand_flash -> lx_nand_flash_backup_metadata_block_number_current; + + /* Set erase count to maximum. */ + min_erase_count = 255; + + /* Loop to find the minimum erase count. */ + for (j = 0; j < nand_flash -> lx_nand_flash_total_blocks; j++) + { + + /* Exclude erase count of bad block. */ + if(nand_flash -> lx_nand_flash_block_status_table[j] != LX_NAND_BLOCK_STATUS_BAD) + { + + /* Check if it has less erase count. */ + if (nand_flash -> lx_nand_flash_erase_count_table[j] < min_erase_count) + { + + /* Update the minimum erase count. */ + min_erase_count = nand_flash -> lx_nand_flash_erase_count_table[j]; + } + } + } + + /* Check if the minimum erase count is larger than zero. */ + if (min_erase_count > 0) + { + + /* Loop to update erase count. */ + for (j = 0; j < nand_flash -> lx_nand_flash_total_blocks; j++) + { + + /* Skip bad blocks. */ + if (nand_flash -> lx_nand_flash_block_status_table[j] != LX_NAND_BLOCK_STATUS_BAD) + { + + /* Update erase count. */ + nand_flash -> lx_nand_flash_erase_count_table[j] = (UCHAR)(nand_flash -> lx_nand_flash_erase_count_table[j] - min_erase_count); + } + } + + /* Update base erase count. */ + nand_flash -> lx_nand_flash_base_erase_count += (ULONG)min_erase_count; + } + + /* Rebuild metadata pages. */ + status = _lx_nand_flash_metadata_build(nand_flash); + + /* Check return status. */ + if (status != LX_SUCCESS) + { + + /* Return error status. */ + return(status); + } + + /* Loop to erase freed blocks. */ + for (j = 0; j < LX_NAND_FLASH_MAX_METADATA_BLOCKS - 1; j++) + { + + /* Get the block number to erase. */ + block = nand_flash -> lx_nand_flash_metadata_block[j]; + + /* Erase the block. */ + 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]); + + /* Check for an error from flash driver. */ + if (status) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, block, 0); +#ifdef LX_THREAD_SAFE_ENABLE + + /* Release the thread safe mutex. */ + tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); +#endif + + /* Return an error. */ + return(LX_ERROR); + } + + /* Check if the block has too many erases. */ + if (nand_flash -> lx_nand_flash_erase_count_table[block] > LX_NAND_FLASH_MAX_ERASE_COUNT_DELTA) + { + + /* Move data from less worn block. */ + _lx_nand_flash_block_data_move(nand_flash, block); + } + else + { + + /* Add the block to free block list. */ + _lx_nand_flash_free_block_list_add(nand_flash, block); + } + + /* Get the block number from backup metadata blocks. */ + block = nand_flash -> lx_nand_flash_backup_metadata_block[j]; + + /* Erase the block. */ + 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]); + + /* Check for an error from flash driver. */ + if (status) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, block, 0); +#ifdef LX_THREAD_SAFE_ENABLE + + /* Release the thread safe mutex. */ + tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); +#endif + + /* Return an error. */ + return(LX_ERROR); + } + + /* Check if the block has too many erases. */ + if (nand_flash -> lx_nand_flash_erase_count_table[block] > LX_NAND_FLASH_MAX_ERASE_COUNT_DELTA) + { + + /* Move data from less worn block. */ + _lx_nand_flash_block_data_move(nand_flash, block); + } + else + { + + /* Add the block to free block list. */ + _lx_nand_flash_free_block_list_add(nand_flash, block); + } + } + + /* Update metadata block list. */ + nand_flash -> lx_nand_flash_metadata_block[0] = (USHORT)nand_flash -> lx_nand_flash_metadata_block_number_current; + + /* Update metadata block list. */ + nand_flash -> lx_nand_flash_backup_metadata_block[0] = (USHORT)nand_flash -> lx_nand_flash_backup_metadata_block_number_current; + + /* Set metadata block count to one. */ + nand_flash -> lx_nand_flash_metadata_block_count = 1; + } + + /* Allocate new block for metadata. */ + status = _lx_nand_flash_block_allocate(nand_flash, &block); + + /* Check return status. */ + if (status != LX_SUCCESS) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, block, 0); + + /* Determine if the error is fatal. */ + if (status != LX_NAND_ERROR_CORRECTED) + { + + /* Return an error. */ + return(LX_ERROR); + } + } + + /* Update next metadata block number. */ + nand_flash -> lx_nand_flash_metadata_block_number_next = block; + + /* Save the new block in metadata block list. */ + nand_flash -> lx_nand_flash_metadata_block[nand_flash -> lx_nand_flash_metadata_block_count] = (USHORT)block; + + /* Set the block status to allocated. */ + status = _lx_nand_flash_block_status_set(nand_flash, block, LX_NAND_BLOCK_STATUS_ALLOCATED); + + /* Check return status. */ + if (status != LX_SUCCESS) + { + + /* Return status. */ + return (status); + } + + /* Allocate new block for backup metadata. */ + status = _lx_nand_flash_block_allocate(nand_flash, &block); + + /* Check return status. */ + if (status != LX_SUCCESS) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, block, 0); + + /* Determine if the error is fatal. */ + if (status != LX_NAND_ERROR_CORRECTED) + { + + /* Return an error. */ + return(LX_ERROR); + } + } + + /* Update next backup metadata block number. */ + nand_flash -> lx_nand_flash_backup_metadata_block_number_next = block; + + /* Save the new block in metadata block list. */ + nand_flash -> lx_nand_flash_backup_metadata_block[nand_flash -> lx_nand_flash_metadata_block_count] = (USHORT)block; + + /* Set the block status to allocated. */ + status = _lx_nand_flash_block_status_set(nand_flash, block, LX_NAND_BLOCK_STATUS_ALLOCATED); + if (status != LX_SUCCESS) + { + return (status); + } + + /* Setup page buffer. */ + page_buffer_ptr = nand_flash -> lx_nand_flash_page_buffer; + + /* Initialize page data. */ + LX_MEMSET(page_buffer_ptr, 0xFF, nand_flash -> lx_nand_flash_bytes_per_page); + + /* Save next block number. */ + LX_UTILITY_LONG_SET(&page_buffer_ptr[LX_NAND_BLOCK_LINK_MAIN_METADATA_OFFSET], nand_flash -> lx_nand_flash_metadata_block_number_next); + + /* Save next block number for backup metadata. */ + LX_UTILITY_LONG_SET(&page_buffer_ptr[LX_NAND_BLOCK_LINK_BACKUP_METADATA_OFFSET], nand_flash -> lx_nand_flash_backup_metadata_block_number_next); + + /* Write metadata. */ + status = _lx_nand_flash_metadata_write(nand_flash, page_buffer_ptr, LX_NAND_PAGE_TYPE_BLOCK_LINK); + + /* Increase metadata block count. */ + nand_flash -> lx_nand_flash_metadata_block_count++; + + /* Return sector not found status. */ + return(status); +} + diff --git a/common/src/lx_nand_flash_block_full_update.c b/common/src/lx_nand_flash_metadata_build.c similarity index 50% rename from common/src/lx_nand_flash_block_full_update.c rename to common/src/lx_nand_flash_metadata_build.c index 698b8ff..b4c123c 100644 --- a/common/src/lx_nand_flash_block_full_update.c +++ b/common/src/lx_nand_flash_metadata_build.c @@ -39,22 +39,19 @@ /* */ /* FUNCTION RELEASE */ /* */ -/* _lx_nand_flash_block_full_update PORTABLE C */ -/* 6.1.7 */ +/* _lx_nand_flash_metadata_build PORTABLE C */ +/* 6.x */ /* AUTHOR */ /* */ -/* William E. Lamie, Microsoft Corporation */ +/* Xiuwen Cai, Microsoft Corporation */ /* */ /* DESCRIPTION */ /* */ -/* This function writes the list of page to logical sector mapping */ -/* when the block is full. */ +/* This function rewrites all metadata pages. */ /* */ /* INPUT */ /* */ /* nand_flash NAND flash instance */ -/* block Block that is full */ -/* erase_count Block erase count */ /* */ /* OUTPUT */ /* */ @@ -62,10 +59,7 @@ /* */ /* CALLS */ /* */ -/* _lx_nand_flash_driver_write Driver flash page write */ -/* _lx_nand_flash_driver_extra_bytes_get Get extra bytes from spare */ -/* _lx_nand_flash_driver_extra_bytes_set Set extra bytes from spare */ -/* _lx_nand_flash_system_error Internal system error handler */ +/* _lx_nand_flash_metadata_write Write metadata */ /* */ /* CALLED BY */ /* */ @@ -75,109 +69,101 @@ /* */ /* DATE NAME DESCRIPTION */ /* */ -/* 05-19-2020 William E. Lamie Initial Version 6.0 */ -/* 09-30-2020 William E. Lamie Modified comment(s), */ -/* resulting in version 6.1 */ -/* 06-02-2021 Bhupendra Naphade Modified comment(s), */ -/* resulting in version 6.1.7 */ +/* xx-xx-xxxx Xiuwen Cai Initial Version 6.x */ /* */ /**************************************************************************/ -UINT _lx_nand_flash_block_full_update(LX_NAND_FLASH *nand_flash, ULONG block, ULONG erase_count) +UINT _lx_nand_flash_metadata_build(LX_NAND_FLASH *nand_flash) { -LX_NAND_PAGE_EXTRA_INFO extra_info; -UINT status; -ULONG i; -ULONG *list_ptr; +UINT status; +LX_NAND_DEVICE_INFO *nand_device_info_page; +UINT page_count; +UINT i; + /* Build device info page. */ + nand_device_info_page = (LX_NAND_DEVICE_INFO*)nand_flash -> lx_nand_flash_page_buffer; + nand_device_info_page -> lx_nand_device_info_signature1 = LX_NAND_DEVICE_INFO_SIGNATURE1; + nand_device_info_page -> lx_nand_device_info_signature2 = LX_NAND_DEVICE_INFO_SIGNATURE2; + nand_device_info_page -> lx_nand_device_info_major_version = LEVELX_MAJOR_VERSION; + nand_device_info_page -> lx_nand_device_info_minor_version = LEVELX_MINOR_VERSION; + nand_device_info_page -> lx_nand_device_info_patch_version = LEVELX_PATCH_VERSION; + nand_device_info_page -> lx_nand_device_info_metadata_block_number = nand_flash -> lx_nand_flash_metadata_block_number; + nand_device_info_page -> lx_nand_device_info_backup_metadata_block_number = nand_flash -> lx_nand_flash_backup_metadata_block_number; + nand_device_info_page -> lx_nand_device_info_base_erase_count = nand_flash -> lx_nand_flash_base_erase_count; - /* Setup pointer to internal buffer. */ - list_ptr = nand_flash -> lx_nand_flash_page_buffer; + /* Write metadata. */ + status = _lx_nand_flash_metadata_write(nand_flash, (UCHAR*)nand_device_info_page, LX_NAND_PAGE_TYPE_DEVICE_INFO); - /* Set the internal buffer of all ones. */ - for (i = 0; i < nand_flash -> lx_nand_flash_words_per_page; i++) + /* Check return status. */ + if (status != LX_SUCCESS) { - - /* Set the buffer to all ones. */ - list_ptr[i] = LX_ALL_ONES; + + /* Return error status. */ + return(status); } - /* Set the initial word to the erase count (this is what is already there!). */ - list_ptr[0] = erase_count; + /* Calculate page count for erase count table. */ + page_count = (nand_flash -> lx_nand_flash_erase_count_table_size + (nand_flash -> lx_nand_flash_bytes_per_page - 1)) / nand_flash -> lx_nand_flash_bytes_per_page; - /* Now walk through the pages in the block to build the list of mapped logical - sectors to pages. */ - i = 1; - while (i < nand_flash -> lx_nand_flash_pages_per_block) + /* Loop to write all the pages. */ + for (i = 0; i < page_count; i++) { - - /* Read the extra bytes of each page to pickup the associated mapping. */ - status = _lx_nand_flash_driver_extra_bytes_get(nand_flash, block, i, (UCHAR *) &extra_info, sizeof(extra_info)); - - /* Check for an error from flash driver. */ - if (status) + + /* Write erase count table. */ + status = _lx_nand_flash_metadata_write(nand_flash, (UCHAR*)(nand_flash -> lx_nand_flash_erase_count_table + + i * nand_flash -> lx_nand_flash_bytes_per_page), + LX_NAND_PAGE_TYPE_ERASE_COUNT_TABLE | i); + + /* Check return status. */ + if (status != LX_SUCCESS) + { + + /* Return error status. */ + return(status); + } + } + + /* Calculate page count for block mapping table. */ + page_count = (nand_flash -> lx_nand_flash_block_mapping_table_size + (nand_flash -> lx_nand_flash_bytes_per_page - 1)) / nand_flash -> lx_nand_flash_bytes_per_page; + + /* Loop to write all the pages. */ + for (i = 0; i < page_count; i++) + { + + /* Write block mapping table. */ + status = _lx_nand_flash_metadata_write(nand_flash, (UCHAR*)(nand_flash -> lx_nand_flash_block_mapping_table + + i * nand_flash -> lx_nand_flash_bytes_per_page / sizeof(*nand_flash -> lx_nand_flash_block_mapping_table)), + LX_NAND_PAGE_TYPE_BLOCK_MAPPING_TABLE | i); + /* Check return status. */ + if (status != LX_SUCCESS) + { + + /* Return error status. */ + return(status); + } + } + + /* Calculate page count for block status table. */ + page_count = (nand_flash -> lx_nand_flash_block_status_table_size + (nand_flash -> lx_nand_flash_bytes_per_page - 1)) / nand_flash -> lx_nand_flash_bytes_per_page; + + /* Loop to write all the pages. */ + for (i = 0; i < page_count; i++) + { + + /* Write block status table. */ + status = _lx_nand_flash_metadata_write(nand_flash, (UCHAR*)(nand_flash -> lx_nand_flash_block_status_table + + i * nand_flash -> lx_nand_flash_bytes_per_page / sizeof(*nand_flash -> lx_nand_flash_block_status_table)), + LX_NAND_PAGE_TYPE_BLOCK_STATUS_TABLE | i); + + /* Check return status. */ + if (status != LX_SUCCESS) { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, block, i); - /* Return the error... no point in continuing. */ + /* Return error status. */ return(status); } - - /* Determine if the extra info indicates the page has not yet been allocated. */ - if (extra_info.lx_nand_page_extra_info_logical_sector == LX_NAND_PAGE_FREE) - { - - /* Block not full, get out of the loop. */ - break; - } - - /* Save the mapping. */ - list_ptr[i] = extra_info.lx_nand_page_extra_info_logical_sector; - - /* Move to next entry. */ - i++; } - - /* Check for a full block. */ - if (i == nand_flash -> lx_nand_flash_pages_per_block) - { - - /* Yes, the block is full. */ - - /* Place the list complete marker so we know the list is intact. */ - list_ptr[i] = LX_NAND_PAGE_LIST_VALID; - - /* At this point we can write the buffer to page 0 of the block. */ - - /* Write the mapping list to page 0. */ - status = _lx_nand_flash_driver_write(nand_flash, block, 0, list_ptr, (nand_flash -> lx_nand_flash_pages_per_block + 1)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, block, 0); - /* Return the error... no point in continuing. */ - return(status); - } - - /* Write the extra bytes for page 0. */ - extra_info.lx_nand_page_extra_info_logical_sector = ((ULONG) LX_NAND_PAGE_FREE) & ~(((ULONG) LX_NAND_BLOCK_EMPTY) | ((ULONG) LX_NAND_BLOCK_FULL)); - status = _lx_nand_flash_driver_extra_bytes_set(nand_flash, block, 0, (UCHAR *) &extra_info, sizeof(extra_info)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, block, 0); - } - } - /* Return status. */ return(status); } diff --git a/common/src/lx_nand_flash_metadata_write.c b/common/src/lx_nand_flash_metadata_write.c new file mode 100644 index 0000000..d14e250 --- /dev/null +++ b/common/src/lx_nand_flash_metadata_write.c @@ -0,0 +1,158 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** LevelX Component */ +/** */ +/** NAND Flash */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define LX_SOURCE_CODE + + +/* Disable ThreadX error checking. */ + +#ifndef LX_DISABLE_ERROR_CHECKING +#define LX_DISABLE_ERROR_CHECKING +#endif + + +/* Include necessary system files. */ + +#include "lx_api.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _lx_nand_flash_metadata_write PORTABLE C */ +/* 6.x */ +/* AUTHOR */ +/* */ +/* Xiuwen Cai, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function writes metadata pages into current metadata block and */ +/* allocates new blocks for metadata. */ +/* */ +/* INPUT */ +/* */ +/* nand_flash NAND flash instance */ +/* main_buffer Main page buffer */ +/* spare_value Value for spare bytes */ +/* */ +/* OUTPUT */ +/* */ +/* return status */ +/* */ +/* CALLS */ +/* */ +/* lx_nand_flash_driver_pages_write Driver pages write */ +/* _lx_nand_flash_metadata_allocate Allocate blocks for metadata */ +/* _lx_nand_flash_system_error Internal system error handler */ +/* */ +/* CALLED BY */ +/* */ +/* Internal LevelX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* xx-xx-xxxx Xiuwen Cai Initial Version 6.x */ +/* */ +/**************************************************************************/ +UINT _lx_nand_flash_metadata_write(LX_NAND_FLASH *nand_flash, UCHAR* main_buffer, ULONG spare_value) +{ + +ULONG block; +ULONG page; +UINT status; +UCHAR *spare_buffer_ptr; + + + /* Setup spare buffer pointer. */ + spare_buffer_ptr = nand_flash -> lx_nand_flash_page_buffer + nand_flash -> lx_nand_flash_bytes_per_page; + + /* Initialize the spare buffer. */ + LX_MEMSET(spare_buffer_ptr, 0xFF, nand_flash -> lx_nand_flash_spare_total_length); + + /* Check if there is enough spare data for metadata block number. */ + if (nand_flash -> lx_nand_flash_spare_data2_length >= 2) + { + + /* Save metadata block number in spare bytes. */ + LX_UTILITY_SHORT_SET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data2_offset], nand_flash -> lx_nand_flash_metadata_block_number); + } + + /* Save metadata type data in spare bytes. */ + LX_UTILITY_LONG_SET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset], spare_value); + + /* Get current metadata block number. */ + block = nand_flash -> lx_nand_flash_metadata_block_number_current; + + /* Get current metadata page number. */ + page = nand_flash -> lx_nand_flash_metadata_block_current_page; + + /* Write the page. */ + status = (nand_flash -> lx_nand_flash_driver_pages_write)(block, page, main_buffer, spare_buffer_ptr, 1); + + /* Check for an error from flash driver. */ + if (status) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, block, 0); + + /* Return an error. */ + return(status); + } + + /* Increase current page for metadata block. */ + nand_flash -> lx_nand_flash_metadata_block_current_page++; + + /* Get current backup metadata block number. */ + block = nand_flash -> lx_nand_flash_backup_metadata_block_number_current; + + /* Get current backup metadata page number. */ + page = nand_flash -> lx_nand_flash_backup_metadata_block_current_page; + + /* Write the page. */ + status = (nand_flash -> lx_nand_flash_driver_pages_write)(block, page, main_buffer, spare_buffer_ptr, 1); + + /* Check for an error from flash driver. */ + if (status) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, block, 0); + + /* Return an error. */ + return(status); + } + + /* Increase current page for backup metadata block. */ + nand_flash -> lx_nand_flash_backup_metadata_block_current_page++; + + /* Allocate new block for metadata if necessary. */ + _lx_nand_flash_metadata_allocate(nand_flash); + + /* Return sector not found status. */ + return(status); +} + diff --git a/common/src/lx_nand_flash_next_block_to_erase_find.c b/common/src/lx_nand_flash_next_block_to_erase_find.c deleted file mode 100644 index ecc6916..0000000 --- a/common/src/lx_nand_flash_next_block_to_erase_find.c +++ /dev/null @@ -1,305 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** LevelX Component */ -/** */ -/** NAND Flash */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -#define LX_SOURCE_CODE - - -/* Disable ThreadX error checking. */ - -#ifndef LX_DISABLE_ERROR_CHECKING -#define LX_DISABLE_ERROR_CHECKING -#endif - - -/* Include necessary system files. */ - -#include "lx_api.h" - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _lx_nand_flash_next_block_to_erase_find PORTABLE C */ -/* 6.1.7 */ -/* AUTHOR */ -/* */ -/* William E. Lamie, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function finds the next block to erase in the NAND flash. */ -/* */ -/* INPUT */ -/* */ -/* nand_flash NAND flash instance */ -/* return_erase_block Returned block to erase */ -/* return_erase_count Returned erase count of block */ -/* return_mapped_pages Returned number of mapped */ -/* pages */ -/* return_obsolete_pages Returned number of obsolete */ -/* pages */ -/* */ -/* OUTPUT */ -/* */ -/* return status */ -/* */ -/* CALLS */ -/* */ -/* _lx_nand_flash_driver_extra_bytes_get Driver block extra bytes get */ -/* _lx_nand_flash_driver_block_status_get */ -/* Driver block status get */ -/* _lx_nand_flash_driver_read Driver page read */ -/* _lx_nand_flash_system_error Internal system error handler */ -/* */ -/* CALLED BY */ -/* */ -/* Internal LevelX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 William E. Lamie Initial Version 6.0 */ -/* 09-30-2020 William E. Lamie Modified comment(s), */ -/* resulting in version 6.1 */ -/* 06-02-2021 Bhupendra Naphade Modified comment(s), */ -/* resulting in version 6.1.7 */ -/* */ -/**************************************************************************/ -UINT _lx_nand_flash_next_block_to_erase_find(LX_NAND_FLASH *nand_flash, ULONG *return_erase_block, ULONG *return_erase_count, ULONG *return_mapped_pages, ULONG *return_obsolete_pages) -{ - -LX_NAND_PAGE_EXTRA_INFO extra_info; -UCHAR block_status; -ULONG *block_word_ptr; -ULONG block; -ULONG page; -ULONG mapped_pages; -ULONG erase_count; -ULONG obsolete_pages; -ULONG min_block_erase = 0; -ULONG min_block_erase_count = 0; -ULONG min_block_obsolete_count = 0; -ULONG min_block_mapped_count = 0; -ULONG max_obsolete_pages = 0; -ULONG max_obsolete_block = 0; -ULONG max_obsolete_erase_count = 0; -ULONG max_obsolete_mapped_count = 0; -ULONG min_system_block_erase_count = 0; -ULONG max_system_block_erase_count = 0; -ULONG erase_count_threshold = 0; -UINT status; - - - /* Initialize the minimum erase count. */ - min_block_erase_count = LX_ALL_ONES; - - /* Initialize the system minimum and maximum erase counts. */ - min_system_block_erase_count = LX_ALL_ONES; - max_system_block_erase_count = 0; - - /* Initialize the maximum obsolete page count. */ - max_obsolete_pages = 0; - - /* Calculate the erase count threshold. */ - if (nand_flash -> lx_nand_flash_free_pages >= nand_flash -> lx_nand_flash_pages_per_block) - { - - /* Calculate erase count threshold by adding constant to the current minimum. */ - erase_count_threshold = nand_flash -> lx_nand_flash_minimum_erase_count + LX_NAND_FLASH_MAX_ERASE_COUNT_DELTA; - } - else - { - - /* When the number of free pages is low, simply pick the block that has the most number of obsolete sectors. */ - erase_count_threshold = LX_ALL_ONES; - } - - /* Set the block word pointer to the internal buffer. */ - block_word_ptr = nand_flash -> lx_nand_flash_page_buffer; - - /* Loop through the blocks to attempt to find the block to erase. */ - for (block = 0; block < nand_flash -> lx_nand_flash_total_blocks; block++) - { - - /* First, check to see if this block is good. */ - status = _lx_nand_flash_driver_block_status_get(nand_flash, block, &block_status); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, block, 0); - - /* Return the error. */ - return(status); - } - - /* Determine if this block is bad. */ - if (block_status != LX_NAND_GOOD_BLOCK) - { - - /* Block is bad, move to the next block. */ - continue; - } - - /* Read page 0 of the block, the first word has the erase count. */ - status = _lx_nand_flash_driver_read(nand_flash, block, 0, block_word_ptr, (nand_flash -> lx_nand_flash_pages_per_block + 1)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, block, 0); - - /* Determine if the error is fatal. */ - if (status != LX_NAND_ERROR_CORRECTED) - { - - /* Return the error. */ - return(status); - } - } - - /* Pickup the erase count from the first word of the block. */ - erase_count = block_word_ptr[0]; - - /* Update the system minimum and maximum erase counts. */ - if (erase_count < min_system_block_erase_count) - min_system_block_erase_count = erase_count; - if (erase_count > max_system_block_erase_count) - max_system_block_erase_count = erase_count; - - /* Compute the number of obsolete and mapped pages for this block. */ - obsolete_pages = 0; - mapped_pages = 0; - - /* Loop through the pages for this block. */ - for (page = 1; page < nand_flash -> lx_nand_flash_pages_per_block; page++) - { - - /* Read the logical sector mapping for this page. */ - status = _lx_nand_flash_driver_extra_bytes_get(nand_flash, block, page, (UCHAR *) &extra_info, sizeof(extra_info)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, block, page); - - /* Return the error. */ - return(status); - } - - /* Is this entry free? */ - if (extra_info.lx_nand_page_extra_info_logical_sector == LX_NAND_PAGE_FREE) - { - - /* Get out of the loop, we are done! */ - break; - } - - /* Is this entry obsolete? */ - else if ((extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_PAGE_VALID) == 0) - { - - /* Increment the number of obsolete pages. */ - obsolete_pages++; - } - else - { - - /* Increment the number of mapped pages. */ - mapped_pages++; - } - } - - /* Determine if we have a block with a new maximum number of obsolete pages. */ - if ((obsolete_pages > max_obsolete_pages) && (erase_count <= erase_count_threshold)) - { - - /* Update the new maximum obsolete pages and related information. */ - max_obsolete_pages = obsolete_pages; - max_obsolete_block = block; - max_obsolete_erase_count = erase_count; - max_obsolete_mapped_count = mapped_pages; - } - else if ((max_obsolete_pages) && (obsolete_pages == max_obsolete_pages) && (erase_count <= erase_count_threshold)) - { - - /* Another block has the same number of obsolete pages. Does this new block have a smaller erase - count? */ - if (erase_count < max_obsolete_erase_count) - { - - /* Yes, choose the block with the smaller erase count. */ - max_obsolete_pages = obsolete_pages; - max_obsolete_block = block; - max_obsolete_erase_count = erase_count; - max_obsolete_mapped_count = mapped_pages; - } - } - - /* Determine if we have a new minimum erase count. */ - if (erase_count < min_block_erase_count) - { - - /* Update the new minimum erase count and related information. */ - min_block_erase_count = erase_count; - min_block_erase = block; - min_block_obsolete_count = obsolete_pages; - min_block_mapped_count = mapped_pages; - } - } - - /* Determine if we can erase the block with the most obsolete pages. */ - if (max_obsolete_pages) - { - - /* Erase the block with the most obsolete pages. */ - *return_erase_block = max_obsolete_block; - *return_erase_count = max_obsolete_erase_count; - *return_obsolete_pages = max_obsolete_pages; - *return_mapped_pages = max_obsolete_mapped_count; - } - else - { - - /* Otherwise, erase the block with the smallest erase count. */ - *return_erase_block = min_block_erase; - *return_erase_count = min_block_erase_count; - *return_obsolete_pages = min_block_obsolete_count; - *return_mapped_pages = min_block_mapped_count; - } - - /* Update the overall minimum and maximum erase count. */ - nand_flash -> lx_nand_flash_minimum_erase_count = min_system_block_erase_count; - nand_flash -> lx_nand_flash_maximum_erase_count = max_system_block_erase_count; - - /* Return success. */ - return(LX_SUCCESS); -} - diff --git a/common/src/lx_nand_flash_open.c b/common/src/lx_nand_flash_open.c index 2397b7d..af5ee6d 100644 --- a/common/src/lx_nand_flash_open.c +++ b/common/src/lx_nand_flash_open.c @@ -40,10 +40,10 @@ /* FUNCTION RELEASE */ /* */ /* _lx_nand_flash_open PORTABLE C */ -/* 6.1.9 */ +/* 6.x */ /* AUTHOR */ /* */ -/* William E. Lamie, Microsoft Corporation */ +/* Xiuwen Cai, Microsoft Corporation */ /* */ /* DESCRIPTION */ /* */ @@ -55,6 +55,11 @@ /* nand_flash NAND flash instance */ /* name Name of NAND flash instance */ /* nand_driver_initialize Driver initialize */ +/* memory_ptr Pointer to memory used by the */ +/* LevelX for this NAND. */ +/* memory_size Size of memory - must at least*/ +/* 7 * total block count + */ +/* 2 * page size */ /* */ /* OUTPUT */ /* */ @@ -63,21 +68,12 @@ /* CALLS */ /* */ /* (nand_driver_initialize) Driver initialize */ +/* _lx_nand_flash_memory_initialize Initialize buffer */ /* _lx_nand_flash_driver_block_status_get */ -/* Driver block status get */ -/* _lx_nand_flash_driver_block_status_set */ -/* Driver block status set */ -/* _lx_nand_flash_driver_extra_bytes_get Driver get extra bytes */ -/* _lx_nand_flash_driver_extra_bytes_set Driver set extra bytes */ -/* _lx_nand_flash_driver_read Driver page read */ -/* _lx_nand_flash_driver_write Driver page write */ -/* _lx_nand_flash_driver_block_erased_verify */ -/* Driver verify block erased */ -/* _lx_nand_flash_driver_block_erase Driver block erase */ -/* _lx_nand_flash_driver_page_erased_verify */ -/* Driver verify page erased */ -/* _lx_nand_flash_block_full_update Write mapping to page 0 */ -/* _lx_nand_flash_logical_sector_find Find logical sector */ +/* Get block status */ +/* lx_nand_flash_driver_pages_read Read pages */ +/* _lx_nand_flash_free_block_list_add Add free block to list */ +/* _lx_nand_flash_mapped_block_list_add Add mapped block to list */ /* _lx_nand_flash_system_error System error handler */ /* tx_mutex_create Create thread-safe mutex */ /* */ @@ -89,38 +85,24 @@ /* */ /* DATE NAME DESCRIPTION */ /* */ -/* 05-19-2020 William E. Lamie Initial Version 6.0 */ -/* 09-30-2020 William E. Lamie Modified comment(s), */ -/* resulting in version 6.1 */ -/* 06-02-2021 Bhupendra Naphade Modified comment(s), */ -/* resulting in version 6.1.7 */ -/* 10-15-2021 Bhupendra Naphade Modified comment(s), */ -/* removed multiple write */ -/* to page 0, */ -/* resulting in version 6.1.9 */ +/* xx-xx-xxxx Xiuwen Cai Initial Version 6.x */ /* */ /**************************************************************************/ -UINT _lx_nand_flash_open(LX_NAND_FLASH *nand_flash, CHAR *name, UINT (*nand_driver_initialize)(LX_NAND_FLASH *)) +UINT _lx_nand_flash_open(LX_NAND_FLASH *nand_flash, CHAR *name, UINT (*nand_driver_initialize)(LX_NAND_FLASH *), + ULONG* memory_ptr, UINT memory_size) { -LX_NAND_PAGE_EXTRA_INFO extra_info; ULONG block; ULONG page; -ULONG found_block, found_page; UCHAR block_status; -ULONG *page_word_ptr; -ULONG temp; -ULONG free_pages; -ULONG obsolete_pages; -ULONG mapped_pages; -ULONG max_mapped_sector; -ULONG erased_count, min_erased_count, max_erased_count; +ULONG block_count; UINT status; LX_NAND_FLASH *tail_ptr; -#ifdef LX_NAND_FLASH_DIRECT_MAPPING_CACHE -ULONG logical_sector; -#endif - +LX_NAND_DEVICE_INFO *nand_device_info_page; +UCHAR *spare_buffer_ptr; +UCHAR *page_buffer_ptr; +ULONG page_type; +UCHAR page_index; LX_INTERRUPT_SAVE_AREA LX_PARAMETER_NOT_USED(name); @@ -132,23 +114,28 @@ LX_INTERRUPT_SAVE_AREA (nand_driver_initialize)(nand_flash); /* Determine if we can support this NAND flash size. */ - if (((nand_flash -> lx_nand_flash_pages_per_block * sizeof(ULONG)) + 8) > nand_flash -> lx_nand_flash_bytes_per_page) - { - - /* Not enough room in page 0 to contain the erase count and logical sector mapping list. */ - - /* Return error. */ - return(LX_ERROR); - } - - /* Determine if the driver supplied a RAM buffer for reading the page. */ - if (nand_flash -> lx_nand_flash_page_buffer == LX_NULL) + 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) { /* Return an error. */ - return(LX_NO_MEMORY); + return(LX_ERROR); } + /* Check if it is new LevelX NAND driver. */ + 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) + { + + /* Return an error. */ + return(LX_ERROR); + } + + /* Check the spare data length. */ + if (nand_flash -> lx_nand_flash_spare_data1_length < sizeof(ULONG)) + { + + /* Return an error. */ + return(LX_ERROR); + } /* Calculate the number of words per block and per page. */ nand_flash -> lx_nand_flash_words_per_page = (nand_flash -> lx_nand_flash_bytes_per_page / sizeof(ULONG)); @@ -156,21 +143,22 @@ LX_INTERRUPT_SAVE_AREA /* Calculate the total pages. */ nand_flash -> lx_nand_flash_total_pages = nand_flash -> lx_nand_flash_total_blocks * nand_flash -> lx_nand_flash_pages_per_block; - - /* Setup default values for the max/min erased counts. */ - min_erased_count = LX_ALL_ONES; - max_erased_count = 0; - /* Default the max mapped sector to 0. */ - max_mapped_sector = 0; + /* Initialize memory buffer. */ + status = _lx_nand_flash_memory_initialize(nand_flash, memory_ptr, memory_size); + if (status != LX_SUCCESS) + { + return(status); + } - /* Setup the block word pointer to the internal buffer area. */ - page_word_ptr = nand_flash -> lx_nand_flash_page_buffer; + /* Initialize block numbers. */ + nand_flash -> lx_nand_flash_metadata_block_number = LX_NAND_BLOCK_UNMAPPED; + nand_flash -> lx_nand_flash_backup_metadata_block_number = LX_NAND_BLOCK_UNMAPPED; + + /* Setup page buffer and spare buffer pointers. */ + page_buffer_ptr = nand_flash -> lx_nand_flash_page_buffer; + spare_buffer_ptr = page_buffer_ptr + nand_flash -> lx_nand_flash_bytes_per_page; - /* Initialize the last found block and page search markers. */ - nand_flash -> lx_nand_flash_found_block_search = 0; - nand_flash -> lx_nand_flash_found_page_search = 1; - /* Loop through the blocks to check for bad blocks and determine the minimum and maximum erase count for each good block. */ for (block = 0; block < nand_flash -> lx_nand_flash_total_blocks; block++) { @@ -197,14 +185,17 @@ LX_INTERRUPT_SAVE_AREA /* Increment the number of bad blocks. */ nand_flash -> lx_nand_flash_bad_blocks++; - + + /* Save the block status. */ + nand_flash -> lx_nand_flash_block_status_table[block] = LX_NAND_BLOCK_STATUS_BAD; + /* Continue to the next block. */ continue; } - /* Now read page 0 of the block, which has the erase count in the first 4 bytes. */ - status = _lx_nand_flash_driver_read(nand_flash, block, 0, page_word_ptr, (nand_flash -> lx_nand_flash_pages_per_block + 1)); - + /* Call driver read function to read page 0. */ + status = (nand_flash -> lx_nand_flash_driver_pages_read)(block, 0, page_buffer_ptr, spare_buffer_ptr, 1); + /* Check for an error from flash driver. */ if (status) { @@ -221,669 +212,248 @@ LX_INTERRUPT_SAVE_AREA } } - /* Is the block erased? */ - if (((page_word_ptr[0] & LX_BLOCK_ERASED) != LX_BLOCK_ERASED) && (page_word_ptr[0] != LX_BLOCK_ERASE_STARTED)) + /* Get the page type. */ + page_type = LX_UTILITY_LONG_GET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset]); + + /* Check if the type is device info. */ + if (page_type == LX_NAND_PAGE_TYPE_DEVICE_INFO) { - - /* No, valid block. Isolate the erased count. */ - erased_count = (page_word_ptr[0] & LX_BLOCK_ERASE_COUNT_MASK); - - /* Is this the new minimum? */ - if (erased_count < min_erased_count) + + /* Get the device info page. */ + nand_device_info_page = (LX_NAND_DEVICE_INFO*)page_buffer_ptr; + + /* Check signature. */ + if (nand_device_info_page -> lx_nand_device_info_signature1 == LX_NAND_DEVICE_INFO_SIGNATURE1 && + nand_device_info_page -> lx_nand_device_info_signature2 == LX_NAND_DEVICE_INFO_SIGNATURE2) { - - /* Yes, remember the new minimum. */ - min_erased_count = erased_count; - } - - /* Is this the new maximum? */ - if (erased_count > max_erased_count) - { - - /* Yes, remember the new maximum. */ - max_erased_count = erased_count; + + /* Save the block numbers. */ + nand_flash -> lx_nand_flash_metadata_block_number = nand_device_info_page -> lx_nand_device_info_metadata_block_number; + nand_flash -> lx_nand_flash_backup_metadata_block_number = nand_device_info_page -> lx_nand_device_info_backup_metadata_block_number; + break; } + } + } - /* If we haven't found any erased counts, we can assume the flash is completely erased and needs to - be setup for the first time. */ - if (min_erased_count == LX_ALL_ONES) + /* Check if we have found the metadata block. */ + if (nand_flash -> lx_nand_flash_metadata_block_number == LX_NAND_BLOCK_UNMAPPED) { - - /* Indicate that this is the initial format. */ - nand_flash -> lx_nand_flash_diagnostic_initial_format = LX_TRUE; - - /* Loop through the blocks to setup the flash the first time. */ - for (block = 0; block < nand_flash -> lx_nand_flash_total_blocks; block++) - { - /* First, check to make sure this block is good. */ - status = _lx_nand_flash_driver_block_status_get(nand_flash, block, &block_status); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, block, 0); - - /* Return an error. */ - return(LX_ERROR); - } - - /* Is this block bad? */ - if (block_status != LX_NAND_GOOD_BLOCK) - { - - /* Yes, this block is bad. */ - - /* Increment the number of bad blocks. */ - nand_flash -> lx_nand_flash_bad_blocks++; - - /* Continue to the next block. */ - continue; - } - - /* Setup the initial erase count to 1. */ - page_word_ptr[0] = (((ULONG) 1)); - - /* Write the initial erase count for the block. */ - status = _lx_nand_flash_driver_write(nand_flash, block, 0, page_word_ptr, LX_NAND_ERASE_COUNT_WRITE_SIZE); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, block, 0); - - /* Attempt to mark this block as bad. */ - status = _lx_nand_flash_driver_block_status_set(nand_flash, block, LX_NAND_BAD_BLOCK); - - /* Check for error in setting the block status. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, block, 0); - - /* Return an error. */ - return(LX_ERROR); - } - - /* Increment the bad block count. */ - nand_flash -> lx_nand_flash_bad_blocks++; - } - else - { - - /* Update the number of free pages. Subtract 1, since page 0 is used for the erase count and list of mapped pages. */ - nand_flash -> lx_nand_flash_free_pages = nand_flash -> lx_nand_flash_free_pages + - nand_flash -> lx_nand_flash_pages_per_block - 1; - } - } - - /* Update the overall minimum and maximum erase count. */ - nand_flash -> lx_nand_flash_minimum_erase_count = 1; - nand_flash -> lx_nand_flash_maximum_erase_count = 1; + /* Not found, return an error. */ + return (LX_ERROR); } - else - { - /* At this point, we have a previously managed flash structure. This needs to be traversed to prepare for the - current flash operation. */ + /* Initialize metadata block numbers and lists. */ + nand_flash -> lx_nand_flash_metadata_block_number_current = nand_flash -> lx_nand_flash_metadata_block_number; + nand_flash -> lx_nand_flash_backup_metadata_block_number_current = nand_flash -> lx_nand_flash_backup_metadata_block_number; + nand_flash -> lx_nand_flash_metadata_block[0] = (USHORT)nand_flash -> lx_nand_flash_metadata_block_number; + nand_flash -> lx_nand_flash_backup_metadata_block[0] = (USHORT)nand_flash -> lx_nand_flash_backup_metadata_block_number; - /* Setup the maximum mapped sector value so all searches are valid. */ - nand_flash -> lx_nand_flash_max_mapped_sector = 0xFFFFFFFF; + /* Found one metadata block. */ + nand_flash -> lx_nand_flash_metadata_block_count = 1; - /* Default the flash block search to an invalid value. */ - nand_flash -> lx_nand_flash_free_block_search = nand_flash -> lx_nand_flash_total_blocks; + /* Clear searched block count. */ + block_count = 0; - /* Loop through the blocks. */ - for (block = 0; block < nand_flash -> lx_nand_flash_total_blocks; block++) + do + { + + /* Initialize next block to unmapped. */ + nand_flash -> lx_nand_flash_metadata_block_number_next = LX_NAND_BLOCK_UNMAPPED; + nand_flash -> lx_nand_flash_backup_metadata_block_number_next = LX_NAND_BLOCK_UNMAPPED; + + /* Loop to read pages in the metadata block. */ + for (page = 0; page < nand_flash -> lx_nand_flash_pages_per_block ; page++) { - - /* First, check to make sure this block is good. */ - status = _lx_nand_flash_driver_block_status_get(nand_flash, block, &block_status); + + /* Call driver read function to read page. */ + status = (nand_flash -> lx_nand_flash_driver_pages_read)(block, page, page_buffer_ptr, spare_buffer_ptr, 1); /* Check for an error from flash driver. */ if (status) { - + /* Call system error handler. */ _lx_nand_flash_system_error(nand_flash, status, block, 0); - - /* Return an error. */ - return(LX_ERROR); - } - /* Is this block bad? */ - if (block_status != LX_NAND_GOOD_BLOCK) - { - - /* Yes, this block is bad. */ - - /* Increment the number of bad blocks. */ - nand_flash -> lx_nand_flash_bad_blocks++; - - /* Continue to the next block. */ - continue; - } - - /* Now read page 0 of the block, which has the erase count in the first 4 bytes. */ - status = _lx_nand_flash_driver_read(nand_flash, block, 0, page_word_ptr, (nand_flash -> lx_nand_flash_pages_per_block + 1)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, block, 0); - /* Determine if the error is fatal. */ if (status != LX_NAND_ERROR_CORRECTED) { - + /* Return an error. */ return(LX_ERROR); } } - /* Is the block erased? */ - if (((page_word_ptr[0] & LX_BLOCK_ERASED) == LX_BLOCK_ERASED) || (page_word_ptr[0] == LX_BLOCK_ERASE_STARTED)) + /* Get page type and page index. */ + page_type = LX_UTILITY_LONG_GET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset]) & (~LX_NAND_PAGE_TYPE_PAGE_NUMBER_MASK); + page_index = LX_UTILITY_LONG_GET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset]) & LX_NAND_PAGE_TYPE_PAGE_NUMBER_MASK; + + /* Process metadata page by type. */ + switch (page_type) { + case LX_NAND_PAGE_TYPE_DEVICE_INFO: - /* This can happen if we were previously in the process of erasing the flash block and a - power interruption occurs. It should only occur once though. */ + /* This page is for device info. */ + nand_device_info_page = (LX_NAND_DEVICE_INFO*)page_buffer_ptr; - /* Is this the first time? */ - if (nand_flash -> lx_nand_flash_diagnostic_erased_block) + /* Get the base erase count. */ + nand_flash -> lx_nand_flash_base_erase_count = nand_device_info_page -> lx_nand_device_info_base_erase_count; + break; + + case LX_NAND_PAGE_TYPE_ERASE_COUNT_TABLE: + + /* Check if page index is valid. */ + if (((ULONG)page_index + 1) * nand_flash -> lx_nand_flash_bytes_per_page > nand_flash -> lx_nand_flash_erase_count_table_size) { - - /* No, this is a potential format error, since this should only happen once in a given - NAND flash format. */ - _lx_nand_flash_system_error(nand_flash, LX_SYSTEM_INVALID_BLOCK, block, 0); + + /* Invalid page index. Return an error. */ + status = LX_ERROR; + break; } - /* Increment the erased block count. */ - nand_flash -> lx_nand_flash_diagnostic_erased_block++; + /* Copy page data to erase count table. */ + 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. */ + page_buffer_ptr, nand_flash -> lx_nand_flash_bytes_per_page); + break; - /* Check to see if the block is erased. */ - status = _lx_nand_flash_driver_block_erased_verify(nand_flash, block); + case LX_NAND_PAGE_TYPE_BLOCK_MAPPING_TABLE: - /* Is the block completely erased? */ - if (status != LX_SUCCESS) + /* Check if page index is valid. */ + if (((ULONG)page_index + 1) * nand_flash -> lx_nand_flash_bytes_per_page > nand_flash -> lx_nand_flash_block_mapping_table_size) { - - /* Is this the first time? */ - if (nand_flash -> lx_nand_flash_diagnostic_re_erase_block) - { - - /* No, this is a potential format error, since this should only happen once in a given - NAND flash format. */ - _lx_nand_flash_system_error(nand_flash, LX_SYSTEM_INVALID_BLOCK, block, 0); - } - /* Increment the erased block diagnostic. */ - nand_flash -> lx_nand_flash_diagnostic_re_erase_block++; - - /* No, the block is not fully erased, erase it again. */ - status = _lx_nand_flash_driver_block_erase(nand_flash, block, max_erased_count); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, block, 0); - - /* Attempt to mark this block as bad. */ - status = _lx_nand_flash_driver_block_status_set(nand_flash, block, LX_NAND_BAD_BLOCK); - - /* Check for error in setting the block status. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, block, 0); - - /* Return an error. */ - return(LX_ERROR); - } - - /* Increment the bad block count. */ - nand_flash -> lx_nand_flash_bad_blocks++; - - /* Continue with next block. */ - continue; - } + /* Invalid page index. Return an error. */ + status = LX_ERROR; + break; } - /* Now read page 0 of the block, which is all ones at this point. */ - status = _lx_nand_flash_driver_read(nand_flash, block, 0, page_word_ptr, (nand_flash -> lx_nand_flash_pages_per_block + 1)); + /* Copy page data to block mapping table. */ + 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. */ + page_buffer_ptr, nand_flash -> lx_nand_flash_bytes_per_page); + break; - /* Check for an error from flash driver. */ - if (status) + case LX_NAND_PAGE_TYPE_BLOCK_STATUS_TABLE: + + /* Check if page index is valid. */ + if (((ULONG)page_index + 1) * nand_flash -> lx_nand_flash_bytes_per_page > nand_flash -> lx_nand_flash_block_status_table_size) { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, block, 0); - /* Attempt to mark this block as bad. */ - status = _lx_nand_flash_driver_block_status_set(nand_flash, block, LX_NAND_BAD_BLOCK); - - /* Check for error in setting the block status. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, block, 0); - - /* Return an error. */ - return(LX_ERROR); - } - - /* Increment the bad block count. */ - nand_flash -> lx_nand_flash_bad_blocks++; - - /* Continue with next block. */ - continue; - } - - /* Write the final erase count for the block. */ - page_word_ptr[0] = max_erased_count; - status = _lx_nand_flash_driver_write(nand_flash, block, 0, page_word_ptr, 1); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, block, 0); - - /* Attempt to mark this block as bad. */ - status = _lx_nand_flash_driver_block_status_set(nand_flash, block, LX_NAND_BAD_BLOCK); - - /* Check for error in setting the block status. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, block, 0); - - /* Return an error. */ - return(LX_ERROR); - } - - /* Increment the bad block count. */ - nand_flash -> lx_nand_flash_bad_blocks++; - - /* Continue with next block. */ - continue; + /* Invalid page index. Return an error. */ + status = LX_ERROR; + break; } - /* Update the number of free pages. */ - nand_flash -> lx_nand_flash_free_pages = nand_flash -> lx_nand_flash_free_pages + - nand_flash -> lx_nand_flash_pages_per_block - 1; + /* Copy page data to block status table. */ + 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. */ + page_buffer_ptr, nand_flash -> lx_nand_flash_bytes_per_page); + break; + + case LX_NAND_PAGE_TYPE_FREE_PAGE: + + /* Found a free page. Update current page. */ + nand_flash -> lx_nand_flash_metadata_block_current_page = page; + nand_flash -> lx_nand_flash_backup_metadata_block_current_page = page; + + /* Skip all the remaining pages. */ + page = nand_flash -> lx_nand_flash_pages_per_block; + break; + + case LX_NAND_PAGE_TYPE_BLOCK_LINK: + + /* Found next blocks. Update next block numbers. */ + nand_flash -> lx_nand_flash_metadata_block_number_next = LX_UTILITY_LONG_GET(&page_buffer_ptr[LX_NAND_BLOCK_LINK_MAIN_METADATA_OFFSET]); + nand_flash -> lx_nand_flash_backup_metadata_block_number_next = LX_UTILITY_LONG_GET(&page_buffer_ptr[LX_NAND_BLOCK_LINK_BACKUP_METADATA_OFFSET]); + + /* Save block numbers in metadata block lists. */ + 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]); + 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]); + + /* Increase metadata block count. */ + nand_flash -> lx_nand_flash_metadata_block_count++; + + break; + + default: + + /* Unknown type, return error. */ + status = LX_ERROR; } - else + + /* Check status. */ + if (status == LX_ERROR) { - /* Check for a format error, an interruption while writing the mapped sector list. */ - if ((page_word_ptr[1] != LX_NAND_PAGE_FREE) && - (page_word_ptr[nand_flash -> lx_nand_flash_pages_per_block] != LX_NAND_PAGE_LIST_VALID)) - { - - /* Increment the invalid mapping counter. */ - nand_flash -> lx_nand_flash_diagnostic_mapping_invalid++; - } - - /* Calculate the number of free pages by traversing the pages in the block. */ - free_pages = 0; - obsolete_pages = 0; - mapped_pages = 0; - for (page = 1; page < nand_flash -> lx_nand_flash_pages_per_block; page++) - { - - /* Read the logical sector mapping for this page. */ - status = _lx_nand_flash_driver_extra_bytes_get(nand_flash, block, page, (UCHAR *) &extra_info, sizeof(extra_info)); + /* Error, break the loop. */ + break; + } - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, block, 0); - - /* Return an error. */ - return(LX_ERROR); - } - - /* Determine if the page is free. */ - if (extra_info.lx_nand_page_extra_info_logical_sector == LX_NAND_PAGE_FREE) - { - - /* The page is free and we know that the pages are allocated sequentially - so there is no need to go further. */ - - /* Increment the free pages counter. */ - free_pages = free_pages + (nand_flash -> lx_nand_flash_pages_per_block - page); - - /* Verify that the same position in the mapped list from page 0 is also free. */ - if (page_word_ptr[page] != LX_NAND_PAGE_FREE) - { - - /* Increment the invalid mapping counter. */ - nand_flash -> lx_nand_flash_diagnostic_mapping_invalid++; - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, LX_SYSTEM_INVALID_FORMAT, block, page); - } - - /* Determine if the associated page is really free... it could be the case that the - page data area was in the process of being written or just completed when a power - interruption occurs before the extra bytes are setup with the logical sector. */ - - /* Read verify the page is erased. */ - status = _lx_nand_flash_driver_page_erased_verify(nand_flash, block, page); - - /* Check for an error from flash driver. */ - if (status == LX_ERROR) - { - - /* Increment the page data not free diagnostic counter. */ - nand_flash -> lx_nand_flash_diagnostic_page_data_not_free++; - - /* Decrement the free page counter and increment the obsolete page counter. */ - free_pages--; - obsolete_pages++; - - /* Now setup the extra info to show this page is obsolete. */ - extra_info.lx_nand_page_extra_info_logical_sector = 0; - status = _lx_nand_flash_driver_extra_bytes_set(nand_flash, block, page, (UCHAR *) &extra_info, sizeof(extra_info)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, block, page); - - /* Return an error. */ - return(LX_ERROR); - } - } - - /* At this point we can break out of the page traversal loop, since nothing else can exist after this page. */ - break; - } - else - { - - /* Determine if the mapping list is not present and the value doesn't match the - logical sector value. */ - if ((page_word_ptr[nand_flash -> lx_nand_flash_pages_per_block] == LX_NAND_PAGE_LIST_VALID) && - ((extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_LOGICAL_SECTOR_MASK) != - (page_word_ptr[page] & LX_NAND_LOGICAL_SECTOR_MASK))) - { - - /* Increment the invalid mapping counter. */ - nand_flash -> lx_nand_flash_diagnostic_mapping_invalid++; - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, LX_SYSTEM_INVALID_FORMAT, block, page); - } - - /* Determine if this mapped page is obsolete. */ - if ((extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_LOGICAL_SECTOR_MASK) == - extra_info.lx_nand_page_extra_info_logical_sector) - { - - /* Yes, page mapping is obsolete. Increment the obsolete count. */ - obsolete_pages++; - - /* Continue looking at next page. */ - continue; - } - - /* Determine if the mapping for this page isn't yet valid. */ - if (extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_PAGE_MAPPING_NOT_VALID) - { - - /* Yes, a power interruption or reset occurred while the sector mapping entry was being written. */ - - /* Increment the obsolete count. */ - obsolete_pages++; - - /* Increment the interrupted mapping counter. */ - nand_flash -> lx_nand_flash_diagnostic_mapping_write_interrupted++; - - /* Invalidate this entry - clearing valid bit, superceded bit and logical sector. */ - extra_info.lx_nand_page_extra_info_logical_sector = 0; - - /* Write it out the page extra information. */ - status = _lx_nand_flash_driver_extra_bytes_set(nand_flash, block, page, (UCHAR *) &extra_info, sizeof(extra_info)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, block, page); - - /* Return an error. */ - return(LX_ERROR); - } - - /* Continue looking at next page. */ - continue; - } - - /* Determine if this page is still mapped. */ - if ((extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_PAGE_VALID) && - (extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_PAGE_SUPERCEDED)) - { - - /* Yes, sector is mapped. Increment the mapped count. */ - mapped_pages++; - - /* Determine if this is a new maximum mapped sector. */ - if ((extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_LOGICAL_SECTOR_MASK) > max_mapped_sector) - { - - /* Remember the maximum mapped logical sector. */ - max_mapped_sector = (extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_LOGICAL_SECTOR_MASK); - } - -#ifdef LX_NAND_FLASH_DIRECT_MAPPING_CACHE - - /* Logical sector is mapped, setup the direct cache. */ - logical_sector = extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_LOGICAL_SECTOR_MASK; - - /* Determine if this logical sector fits in the logical sector direct cache mapping. */ - if (logical_sector < LX_NAND_SECTOR_MAPPING_CACHE_SIZE) - { - - /* Remember the mapping for this logical sector. */ - nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_block = (USHORT) block; - nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_page = (USHORT) page; - } -#endif - /* Continue looking at next page. */ - continue; - } - - /* At this point, the page was in the process of being superceded. */ - - /* Determine if this is a new maximum mapped sector. */ - if ((extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_LOGICAL_SECTOR_MASK) > max_mapped_sector) - { - - /* Remember the maximum mapped logical sector. */ - max_mapped_sector = (extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_LOGICAL_SECTOR_MASK); - } - - /* Increment the being obsoleted count. */ - nand_flash -> lx_nand_flash_diagnostic_page_being_obsoleted++; - - /* Save the currently mapped pages. */ - temp = nand_flash -> lx_nand_flash_mapped_pages; - - /* Indicate all the pages are mapped for the purpose of this search. */ - nand_flash -> lx_nand_flash_mapped_pages = nand_flash -> lx_nand_flash_total_pages; - - /* Yes, this block was about to become obsolete. Perform a search for a logical sector entry that - has both of these bits set. */ - _lx_nand_flash_logical_sector_find(nand_flash, (extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_LOGICAL_SECTOR_MASK), - LX_TRUE, &found_block, &found_page); - - /* Read page 0 data again. */ - status = _lx_nand_flash_driver_read(nand_flash, block, 0, page_word_ptr, (nand_flash -> lx_nand_flash_pages_per_block + 1)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, block, 0); - - /* Determine if the error is fatal. */ - if (status != LX_NAND_ERROR_CORRECTED) - { - - /* Return an error. */ - return(LX_ERROR); - } - } - - /* Restore the number of mapped pages. */ - nand_flash -> lx_nand_flash_mapped_pages = temp; - - /* Determine if the new logical sector entry is present. */ - if (found_page) - { - - /* Yes, make the current entry obsolete in favor of the new entry. */ - - /* Increment the obsolete count. */ - obsolete_pages++; - - /* Clear the valid bit. */ - extra_info.lx_nand_page_extra_info_logical_sector = extra_info.lx_nand_page_extra_info_logical_sector & ~((ULONG) LX_NAND_PAGE_VALID); - - /* Write it out the page extra information. */ - status = _lx_nand_flash_driver_extra_bytes_set(nand_flash, block, page, (UCHAR *) &extra_info, sizeof(extra_info)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, block, page); - - /* Return an error. */ - return(LX_ERROR); - } - - /* Is this the first time? */ - if (nand_flash -> lx_nand_flash_diagnostic_page_obsoleted) - { - - /* No, this is a potential format error, since this should only happen once in a given - NAND flash format. */ - _lx_nand_flash_system_error(nand_flash, LX_SYSTEM_INVALID_SECTOR_MAP, block, page); - } - - /* Increment the obsoleted count. */ - nand_flash -> lx_nand_flash_diagnostic_page_obsoleted++; - -#ifdef LX_NAND_FLASH_DIRECT_MAPPING_CACHE - - /* Logical sector is mapped, setup the direct cache. */ - logical_sector = extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_LOGICAL_SECTOR_MASK; - - /* Determine if this logical sector fits in the logical sector direct cache mapping. */ - if (logical_sector < LX_NAND_SECTOR_MAPPING_CACHE_SIZE) - { - - /* Remember the mapping for this logical sector. */ - nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_block = (USHORT) found_block; - nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_page = (USHORT) found_page; - } -#endif - } - else - { - - /* A new page was not found. Increment the number of mapped pages. */ - mapped_pages++; - -#ifdef LX_NAND_FLASH_DIRECT_MAPPING_CACHE - - /* Logical sector is mapped, setup the direct cache. */ - logical_sector = extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_LOGICAL_SECTOR_MASK; - - /* Determine if this logical sector fits in the logical sector direct cache mapping. */ - if (logical_sector < LX_NAND_SECTOR_MAPPING_CACHE_SIZE) - { - - /* Remember the mapping for this logical sector. */ - nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_block = (USHORT) block; - nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_page = (USHORT) page; - } -#endif - } - } - } - - /* Update the number of free, obsolete, and mapped pages. */ - nand_flash -> lx_nand_flash_free_pages = nand_flash -> lx_nand_flash_free_pages + free_pages; - nand_flash -> lx_nand_flash_mapped_pages = nand_flash -> lx_nand_flash_mapped_pages + mapped_pages; - nand_flash -> lx_nand_flash_obsolete_pages = nand_flash -> lx_nand_flash_obsolete_pages + obsolete_pages; - - /* Determine if the mapping list needs to be written to the flash. */ - if ((free_pages == 0) && (page_word_ptr[1] == LX_ALL_ONES)) - { - - /* Yes, the mapping list should be written to page 0. */ - _lx_nand_flash_block_full_update(nand_flash, block, page_word_ptr[0]); - - /* Read page 0 data again. */ - status = _lx_nand_flash_driver_read(nand_flash, block, 0, page_word_ptr, (nand_flash -> lx_nand_flash_pages_per_block + 1)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, block, 0); - - /* Determine if the error is fatal. */ - if (status != LX_NAND_ERROR_CORRECTED) - { - - /* Return an error. */ - return(LX_ERROR); - } - } - } - } } - /* Update the overall minimum and maximum erase count. */ - nand_flash -> lx_nand_flash_minimum_erase_count = min_erased_count; - nand_flash -> lx_nand_flash_maximum_erase_count = max_erased_count; - - /* Determine if we need to update the free sector search pointer. */ - if (nand_flash -> lx_nand_flash_free_block_search == nand_flash -> lx_nand_flash_total_blocks) + /* Check if we have reached the last page. */ + if (page == nand_flash -> lx_nand_flash_pages_per_block) { - - /* Just start at the beginning. */ - nand_flash -> lx_nand_flash_free_block_search = 0; + + /* Move to next block. */ + nand_flash -> lx_nand_flash_metadata_block_number_current = nand_flash -> lx_nand_flash_metadata_block_number_next; + nand_flash -> lx_nand_flash_backup_metadata_block_number_current = nand_flash -> lx_nand_flash_backup_metadata_block_number_next; + + /* Make sure the block is valid. */ + if (nand_flash -> lx_nand_flash_metadata_block_number_current == LX_NAND_BLOCK_UNMAPPED) + { + + /* Error, break the loop. */ + break; + } + + /* Get the block to process. */ + block = nand_flash -> lx_nand_flash_metadata_block_number_current; + } + + /* Increase the processed block number. */ + block_count++; + + /* If block count is larger than total blocks, there is an error. */ + if (block_count >= nand_flash -> lx_nand_flash_total_blocks) + { + + /* Break the loop. */ + break; + } + } while (nand_flash -> lx_nand_flash_metadata_block_current_page == 0 && status != LX_ERROR); + + /* Check if metadata page is processed correctly. */ + if (nand_flash -> lx_nand_flash_metadata_block_current_page == 0 || status == LX_ERROR) + { + + /* Return an error. */ + return(LX_ERROR); + } + + /* Loop to build free and mapped block lists. */ + for (block = 0; block < nand_flash -> lx_nand_flash_total_blocks; block++) + { + + /* Check for free blocks. */ + if (nand_flash -> lx_nand_flash_block_status_table[block] == LX_NAND_BLOCK_STATUS_FREE) + { + + /* Add the block to free block list. */ + _lx_nand_flash_free_block_list_add(nand_flash, block); + } + + /* Check for mapped blocks. */ + if (nand_flash -> lx_nand_flash_block_mapping_table[block] != LX_NAND_BLOCK_UNMAPPED) + { + + /* Add the block to free block list. */ + _lx_nand_flash_mapped_block_list_add(nand_flash, block); } } + #ifdef LX_THREAD_SAFE_ENABLE /* If the thread safe option is enabled, create a ThreadX mutex that will be used in all external APIs @@ -902,16 +472,6 @@ LX_INTERRUPT_SAVE_AREA } #endif - /* Enable the sector mapping cache. */ - nand_flash -> lx_nand_flash_sector_mapping_cache_enabled = LX_TRUE; - - /* Initialize the last found block and page search markers. */ - nand_flash -> lx_nand_flash_found_block_search = 0; - nand_flash -> lx_nand_flash_found_page_search = 1; - - /* Remember the maximum mapped sector. */ - nand_flash -> lx_nand_flash_max_mapped_sector = max_mapped_sector; - /* Lockout interrupts. */ LX_DISABLE diff --git a/common/src/lx_nand_flash_partial_defragment.c b/common/src/lx_nand_flash_partial_defragment.c index a5fa144..35bd65d 100644 --- a/common/src/lx_nand_flash_partial_defragment.c +++ b/common/src/lx_nand_flash_partial_defragment.c @@ -40,7 +40,7 @@ /* FUNCTION RELEASE */ /* */ /* _lx_nand_flash_partial_defragment PORTABLE C */ -/* 6.1.7 */ +/* 6.x */ /* AUTHOR */ /* */ /* William E. Lamie, Microsoft Corporation */ @@ -62,9 +62,7 @@ /* */ /* CALLS */ /* */ -/* _lx_nand_flash_block_reclaim Reclaim a NAND flash block */ -/* tx_mutex_get Get thread protection */ -/* tx_mutex_put Release thread protection */ +/* None */ /* */ /* CALLED BY */ /* */ @@ -80,48 +78,19 @@ /* resulting in version 6.1 */ /* 06-02-2021 Bhupendra Naphade Modified comment(s), */ /* resulting in version 6.1.7 */ +/* xx-xx-xxxx Xiuwen Cai Modified comment(s), */ +/* deprecated this API, */ +/* resulting in version 6.x */ /* */ /**************************************************************************/ UINT _lx_nand_flash_partial_defragment(LX_NAND_FLASH *nand_flash, UINT max_blocks) { -ULONG i; + LX_PARAMETER_NOT_USED(nand_flash); + LX_PARAMETER_NOT_USED(max_blocks); - -#ifdef LX_THREAD_SAFE_ENABLE - - /* Obtain the thread safe mutex. */ - tx_mutex_get(&nand_flash -> lx_nand_flash_mutex, TX_WAIT_FOREVER); -#endif - - /* Determine if the maximum number of blocks exceeds the total blocks in this flash instance. */ - if (max_blocks >= nand_flash -> lx_nand_flash_total_blocks) - { - - /* Adjust the maximum to the total number of blocks. */ - max_blocks = nand_flash -> lx_nand_flash_total_blocks; - } - - /* Loop for max number of blocks, while there are obsolete count. */ - for (i = 0; i < max_blocks; i++) - { - - /* Determine if there is any more defragment work. */ - if (nand_flash -> lx_nand_flash_obsolete_pages == 0) - break; - - /* Call the block reclaim function to defragment. */ - _lx_nand_flash_block_reclaim(nand_flash); - } - -#ifdef LX_THREAD_SAFE_ENABLE - - /* Release the thread safe mutex. */ - tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); -#endif - - /* Return successful completion. */ - return(LX_SUCCESS); + /* Return not supported. */ + return(LX_NOT_SUPPORTED); } diff --git a/common/src/lx_nand_flash_physical_page_allocate.c b/common/src/lx_nand_flash_physical_page_allocate.c deleted file mode 100644 index 1d46f43..0000000 --- a/common/src/lx_nand_flash_physical_page_allocate.c +++ /dev/null @@ -1,396 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** LevelX Component */ -/** */ -/** NAND Flash */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -#define LX_SOURCE_CODE - - -/* Disable ThreadX error checking. */ - -#ifndef LX_DISABLE_ERROR_CHECKING -#define LX_DISABLE_ERROR_CHECKING -#endif - - -/* Include necessary system files. */ - -#include "lx_api.h" - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _lx_nand_flash_physical_page_allocate PORTABLE C */ -/* 6.1.7 */ -/* AUTHOR */ -/* */ -/* William E. Lamie, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function allocates a free page for mapping to a */ -/* logical sector. */ -/* */ -/* INPUT */ -/* */ -/* nand_flash NAND flash instance */ -/* block Destination for block */ -/* page Destination for page */ -/* erase_count Destination for erase count */ -/* */ -/* OUTPUT */ -/* */ -/* return status */ -/* */ -/* CALLS */ -/* */ -/* _lx_nand_flash_driver_extra_bytes_get Driver get extra bytes */ -/* _lx_nand_flash_driver_extra_bytes_set Driver set extra bytes */ -/* _lx_nand_flash_driver_block_status_get */ -/* Driver block status get */ -/* _lx_nand_flash_driver_page_erased_verify */ -/* Driver verify page erased */ -/* _lx_nand_flash_driver_read Driver page read */ -/* _lx_nand_flash_block_full_update Update page 0 with list of */ -/* mapped pages */ -/* _lx_nand_flash_system_error Internal system error handler */ -/* */ -/* CALLED BY */ -/* */ -/* Internal LevelX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 William E. Lamie Initial Version 6.0 */ -/* 09-30-2020 William E. Lamie Modified comment(s), */ -/* resulting in version 6.1 */ -/* 06-02-2021 Bhupendra Naphade Modified comment(s), */ -/* resulting in version 6.1.7 */ -/* */ -/**************************************************************************/ -UINT _lx_nand_flash_physical_page_allocate(LX_NAND_FLASH *nand_flash, ULONG *block, ULONG *page, ULONG *erase_count) -{ - -LX_NAND_PAGE_EXTRA_INFO extra_info; -UCHAR block_status; -ULONG search_block; -ULONG search_page; -ULONG *word_ptr; -ULONG i, j; -UINT status; - - - /* Increment the number of page allocation requests. */ - nand_flash -> lx_nand_flash_diagnostic_page_allocates++; - - /* Initialize the return parameters. */ - *block = (ULONG) 0; - *page = (ULONG) 0; - *erase_count = nand_flash -> lx_nand_flash_minimum_erase_count; - - /* Determine if there are any free pages. */ - if (nand_flash -> lx_nand_flash_free_pages == 0) - { - - /* Increment the number of failed allocations. */ - nand_flash -> lx_nand_flash_diagnostic_page_allocate_errors++; - - /* No free pages, return . */ - return(LX_NO_PAGES); - } - - /* Pickup the search for a free page at the specified block. */ - search_block = nand_flash -> lx_nand_flash_free_block_search; - - /* Loop through the blocks to find a free page. */ - for (i = 0; i < nand_flash -> lx_nand_flash_total_blocks; i++) - { - - /* First, check to see if this block is good. */ - status = _lx_nand_flash_driver_block_status_get(nand_flash, search_block, &block_status); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, search_block, 0); - - /* Return the error. */ - return(status); - } - - /* Determine if this block is bad. */ - if (block_status != LX_NAND_GOOD_BLOCK) - { - - /* Move to next search block. */ - search_block++; - - /* Have we wrapped around yet? */ - if (search_block >= nand_flash -> lx_nand_flash_total_blocks) - { - - /* Reset the search block to the beginning. */ - search_block = 0; - } - - /* Block is bad, move to the next block. */ - continue; - } - - /* Read the extra bytes of page 0. This will tell us if the page has any free entries. */ - status = _lx_nand_flash_driver_extra_bytes_get(nand_flash, search_block, 0, (UCHAR *) &extra_info, sizeof(extra_info)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, search_block, 0); - - /* Return the error... no point in continuing. */ - return(status); - } - - /* Determine if there are any free entries. */ - if ((extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_BLOCK_FULL) == 0) - { - - /* This block is full... go to the next block. */ - search_block++; - - /* Have we wrapped around yet? */ - if (search_block >= nand_flash -> lx_nand_flash_total_blocks) - { - - /* Reset the search block to the beginning. */ - search_block = 0; - } - - /* Block is bad, move to the next block. */ - continue; - } - - /* Now check to see if page 0 has been written to. When the block is full, page 0 is written with the mapping of pages - to logical sectors in this block - only when the block becomes full. If the block has additional pages free, page 0 is all 0xFFs. */ - status = _lx_nand_flash_driver_read(nand_flash, search_block, 0, nand_flash -> lx_nand_flash_page_buffer, nand_flash -> lx_nand_flash_words_per_page); - - /* Check for an error... an error here indicates the block does not have any free pages. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, search_block, 0); - - /* Determine if the error is fatal. */ - if (status != LX_NAND_ERROR_CORRECTED) - { - - /* Return the error. */ - return(status); - } - } - - /* Setup pointer to the page 0 data. */ - word_ptr = nand_flash -> lx_nand_flash_page_buffer; - - /* Pickup the block erase count (first word in the page 0 data area). */ - if (*word_ptr != LX_ALL_ONES) - *erase_count = *word_ptr; - - /* Now determine if the remaining words are all ones, i.e. haven't been written to. */ - j = 1; - while (j < (nand_flash -> lx_nand_flash_pages_per_block + 1)) - { - - /* Has this word been written to? */ - if (word_ptr[j] != LX_ALL_ONES) - break; - - /* Move to next word. */ - j++; - } - - /* Does this block have any free pages? */ - if (j < (nand_flash -> lx_nand_flash_pages_per_block + 1)) - { - - /* Move to next search block. */ - search_block++; - - /* Have we wrapped around yet? */ - if (search_block >= nand_flash -> lx_nand_flash_total_blocks) - { - - /* Reset the search block to the beginning. */ - search_block = 0; - } - - /* No, the data area has been written to. Simply move to the next block. */ - continue; - } - - /* Now search for an available page within the block. */ - search_page = 1; - while (search_page < nand_flash -> lx_nand_flash_pages_per_block) - { - - /* Read the extra information for this page to see if there is a sector mapping. */ - status = _lx_nand_flash_driver_extra_bytes_get(nand_flash, search_block, search_page, (UCHAR *) &extra_info, sizeof(extra_info)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, search_block, search_page); - - /* Return the error. */ - return(status); - } - - /* Now determine if this page is mapped or free. */ - if (extra_info.lx_nand_page_extra_info_logical_sector == LX_NAND_PAGE_FREE) - { - - /* Now make sure the data area of this page is free. */ - status = _lx_nand_flash_driver_page_erased_verify(nand_flash, search_block, search_page); - - /* Is the page free? */ - if (status != LX_SUCCESS) - { - - /* No, the page is not actually free. For now, simply mark the extra info area to indicate - the page is not available and continue our search. */ - extra_info.lx_nand_page_extra_info_logical_sector = 0; - - /* Decrease the number of free pages. */ - nand_flash -> lx_nand_flash_free_pages--; - - /* Increase the number of obsolete pages. */ - nand_flash -> lx_nand_flash_obsolete_pages++; - - /* Write out the extra info for this page. */ - status = _lx_nand_flash_driver_extra_bytes_set(nand_flash, search_block, search_page, (UCHAR *) &extra_info, sizeof(extra_info)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, search_block, search_page); - - /* Return the error. */ - return(status); - } - - /* Determine if this is the last entry of the block. */ - if (search_page == (nand_flash -> lx_nand_flash_pages_per_block - 1)) - { - - /* Yes, we need to update page 0 of the block with the list of mapped - pages for this block. */ - _lx_nand_flash_block_full_update(nand_flash, search_block, *erase_count); - } - } - else - { - - /* Yes, we have found a free page in this block. Get out of the page search loop. */ - break; - } - } - - /* Move to next search page. */ - search_page++; - } - - /* Determine if we have found the free block. */ - if (search_page < nand_flash -> lx_nand_flash_pages_per_block) - { - - /* Remember the block to search. */ - nand_flash -> lx_nand_flash_free_block_search = search_block; - - /* Determine if the allocated page is the last one in this block. */ - if (search_page == (nand_flash -> lx_nand_flash_pages_per_block - 1)) - { - - /* Yes, move to the next block. */ - nand_flash -> lx_nand_flash_free_block_search++; - - /* Have we wrapped around yet? */ - if (nand_flash -> lx_nand_flash_free_block_search >= nand_flash -> lx_nand_flash_total_blocks) - { - - /* Wrap condition - reset the search block to the beginning. */ - nand_flash -> lx_nand_flash_free_block_search = 0; - } - } - - /* Prepare the return information. */ - *block = search_block; - *page = search_page; - - /* Determine if this is the first data page of the block. */ - if (search_page == 1) - { - - /* Yes, we need to update the extra bytes of page 0 to indicate the block is no longer empty. */ - extra_info.lx_nand_page_extra_info_logical_sector = ((ULONG) LX_NAND_PAGE_FREE) & ~((ULONG) LX_NAND_BLOCK_EMPTY); - status = _lx_nand_flash_driver_extra_bytes_set(nand_flash, search_block, 0, (UCHAR *) &extra_info, sizeof(extra_info)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, search_block, 0); - } - } - - /* Return success! */ - return(LX_SUCCESS); - } - - /* Move to next search block. */ - search_block++; - - /* Have we wrapped around yet? */ - if (search_block >= nand_flash -> lx_nand_flash_total_blocks) - { - - /* Reset the search block to the beginning. */ - search_block = 0; - } - } - - /* Increment the number of failed allocations. */ - nand_flash -> lx_nand_flash_diagnostic_page_allocate_errors++; - - /* Return error. */ - return(LX_NO_PAGES); -} - diff --git a/common/src/lx_nand_flash_sector_mapping_cache_invalidate.c b/common/src/lx_nand_flash_sector_mapping_cache_invalidate.c deleted file mode 100644 index b54b6ff..0000000 --- a/common/src/lx_nand_flash_sector_mapping_cache_invalidate.c +++ /dev/null @@ -1,154 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** LevelX Component */ -/** */ -/** NAND Flash */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -#define LX_SOURCE_CODE - - -/* Disable ThreadX error checking. */ - -#ifndef LX_DISABLE_ERROR_CHECKING -#define LX_DISABLE_ERROR_CHECKING -#endif - - -/* Include necessary system files. */ - -#include "lx_api.h" - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _lx_nand_flash_sector_mapping_cache_invalidate PORTABLE C */ -/* 6.1.7 */ -/* AUTHOR */ -/* */ -/* William E. Lamie, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function invalidates the sector's entry in the NAND flash */ -/* cache. */ -/* */ -/* INPUT */ -/* */ -/* nand_flash NAND flash instance */ -/* logical_sector Logical sector */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Internal LevelX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 William E. Lamie Initial Version 6.0 */ -/* 09-30-2020 William E. Lamie Modified comment(s), */ -/* resulting in version 6.1 */ -/* 06-02-2021 Bhupendra Naphade Modified comment(s), */ -/* resulting in version 6.1.7 */ -/* */ -/**************************************************************************/ -VOID _lx_nand_flash_sector_mapping_cache_invalidate(LX_NAND_FLASH *nand_flash, ULONG logical_sector) -{ - -#ifndef LX_NAND_FLASH_DIRECT_MAPPING_CACHE -ULONG i; -LX_NAND_SECTOR_MAPPING_CACHE_ENTRY *sector_mapping_cache_entry_ptr; -#endif - - /* Determine if the sector mapping cache is enabled. */ - if (nand_flash -> lx_nand_flash_sector_mapping_cache_enabled) - { - -#ifndef LX_NAND_FLASH_DIRECT_MAPPING_CACHE - - /* Calculate the starting index of the sector mapping cache for this sector entry. */ - i = (logical_sector & LX_NAND_SECTOR_MAPPING_CACHE_HASH_MASK) * LX_NAND_SECTOR_MAPPING_CACHE_DEPTH; - - /* Build a pointer to the cache entry. */ - sector_mapping_cache_entry_ptr = &nand_flash -> lx_nand_flash_sector_mapping_cache[i]; - - /* Determine if the sector is in the sector mapping cache - assuming the depth of the sector - mapping cache is LX_NAND_SECTOR_MAPPING_CACHE_DEPTH entries. */ - if ((sector_mapping_cache_entry_ptr -> lx_nand_sector_mapping_cache_logical_sector) == (logical_sector | LX_NAND_SECTOR_MAPPING_CACHE_ENTRY_VALID)) - { - - /* Move all cache entries up and invalidate the last entry. */ - *(sector_mapping_cache_entry_ptr) = *(sector_mapping_cache_entry_ptr + 1); - *(sector_mapping_cache_entry_ptr + 1) = *(sector_mapping_cache_entry_ptr + 2); - *(sector_mapping_cache_entry_ptr + 2) = *(sector_mapping_cache_entry_ptr + 3); - - /* Invalidate the last entry. */ - (sector_mapping_cache_entry_ptr + 3) -> lx_nand_sector_mapping_cache_logical_sector = 0; - } - else if (((sector_mapping_cache_entry_ptr + 1) -> lx_nand_sector_mapping_cache_logical_sector) == (logical_sector | LX_NAND_SECTOR_MAPPING_CACHE_ENTRY_VALID)) - { - - /* Move all subsequent cache entries up and invalidate the last entry. */ - *(sector_mapping_cache_entry_ptr + 1) = *(sector_mapping_cache_entry_ptr + 2); - *(sector_mapping_cache_entry_ptr + 2) = *(sector_mapping_cache_entry_ptr + 3); - - /* Invalidate the last entry. */ - (sector_mapping_cache_entry_ptr + 3) -> lx_nand_sector_mapping_cache_logical_sector = 0; - } - else if (((sector_mapping_cache_entry_ptr + 2) -> lx_nand_sector_mapping_cache_logical_sector) == (logical_sector | LX_NAND_SECTOR_MAPPING_CACHE_ENTRY_VALID)) - { - - /* Move all subsequent cache entries up and invalidate the last entry. */ - *(sector_mapping_cache_entry_ptr + 2) = *(sector_mapping_cache_entry_ptr + 3); - - /* Invalidate the last entry. */ - (sector_mapping_cache_entry_ptr + 3) -> lx_nand_sector_mapping_cache_logical_sector = 0; - } - else if (((sector_mapping_cache_entry_ptr + 3) -> lx_nand_sector_mapping_cache_logical_sector) == (logical_sector | LX_NAND_SECTOR_MAPPING_CACHE_ENTRY_VALID)) - { - - /* Simply invalidate the last entry. */ - (sector_mapping_cache_entry_ptr + 3) -> lx_nand_sector_mapping_cache_logical_sector = 0; - } -#else - - /* Direct mapping cache is defined. */ - - /* Determine if this logical sector fits in the logical sector cache mapping. */ - if (logical_sector < LX_NAND_SECTOR_MAPPING_CACHE_SIZE) - { - - /* Yes, invalidate the logical sector cache. */ - nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_block = 0; - nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_page = 0; - } -#endif - } -} - diff --git a/common/src/lx_nand_flash_sector_read.c b/common/src/lx_nand_flash_sector_read.c index 416f34a..218c902 100644 --- a/common/src/lx_nand_flash_sector_read.c +++ b/common/src/lx_nand_flash_sector_read.c @@ -40,10 +40,10 @@ /* FUNCTION RELEASE */ /* */ /* _lx_nand_flash_sector_read PORTABLE C */ -/* 6.1.7 */ +/* 6.x */ /* AUTHOR */ /* */ -/* William E. Lamie, Microsoft Corporation */ +/* Xiuwen Cai, Microsoft Corporation */ /* */ /* DESCRIPTION */ /* */ @@ -63,8 +63,8 @@ /* */ /* CALLS */ /* */ -/* _lx_nand_flash_driver_read Driver page read */ -/* _lx_nand_flash_logical_sector_find Find logical sector */ +/* _lx_nand_flash_block_find Find the mapped block */ +/* lx_nand_flash_driver_pages_read Read pages */ /* _lx_nand_flash_system_error Internal system error handler */ /* tx_mutex_get Get thread protection */ /* tx_mutex_put Release thread protection */ @@ -77,22 +77,20 @@ /* */ /* DATE NAME DESCRIPTION */ /* */ -/* 05-19-2020 William E. Lamie Initial Version 6.0 */ -/* 09-30-2020 William E. Lamie Modified comment(s), */ -/* resulting in version 6.1 */ -/* 06-02-2021 Bhupendra Naphade Modified comment(s), */ -/* resulting in version 6.1.7 */ +/* xx-xx-xxxx Xiuwen Cai Initial Version 6.x */ /* */ /**************************************************************************/ UINT _lx_nand_flash_sector_read(LX_NAND_FLASH *nand_flash, ULONG logical_sector, VOID *buffer) { UINT status; -ULONG found_block; -ULONG found_page; ULONG i; ULONG *word_ptr; - +ULONG block; +USHORT block_status; +UCHAR *spare_buffer_ptr; +ULONG available_pages; +LONG page; #ifdef LX_THREAD_SAFE_ENABLE @@ -104,67 +102,129 @@ ULONG *word_ptr; nand_flash -> lx_nand_flash_diagnostic_sector_read_requests++; /* See if we can find the sector in the current mapping. */ - _lx_nand_flash_logical_sector_find(nand_flash, logical_sector, LX_FALSE, &found_block, &found_page); - - /* Determine if the logical sector mapping was found. */ - if (found_page) - { - - /* Yes, we were able to find the logical sector to page mapping. */ - - /* Read the data from the page. */ - status = _lx_nand_flash_driver_read(nand_flash, found_block, found_page, buffer, nand_flash -> lx_nand_flash_words_per_page); + status = _lx_nand_flash_block_find(nand_flash, logical_sector, &block, &block_status); - /* Check for an error from flash driver. */ - if (status) + /* Check return status. */ + if (status != LX_SUCCESS) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, block, 0); + + /* Determine if the error is fatal. */ + if (status != LX_NAND_ERROR_CORRECTED) { +#ifdef LX_THREAD_SAFE_ENABLE + + /* Release the thread safe mutex. */ + tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); +#endif + /* Return an error. */ + return(LX_ERROR); + } + } + + /* Determine if the block is mapped. */ + if (block != LX_NAND_BLOCK_UNMAPPED) + { - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, found_block, found_page); - - /* Determine if the error was corrected. */ - if (status == LX_NAND_ERROR_CORRECTED) + /* Setup spare buffer pointer. */ + spare_buffer_ptr = (UCHAR*)nand_flash -> lx_nand_flash_page_buffer; + + /* Get available pages in this block. */ + 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; + + /* Determine if the pages are recorded sequentially. */ + if (block_status & LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL) + { + + /* Loop to search the logical page. */ + for (page = (LONG)available_pages - 1; page >= 0; page--) { - - /* Yes, we were able to read this page successfully with error correction. */ + + /* Read a page. */ + status = (nand_flash -> lx_nand_flash_driver_pages_read)(block, (ULONG)page, (UCHAR*)buffer, spare_buffer_ptr, 1); - /* Change the status to LX_SUCCESS. */ - status = LX_SUCCESS; - } - else - { - - /* Adjust return status. */ - status = LX_ERROR; + /* Check for an error from flash driver. */ + if (status) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, block, 0); +#ifdef LX_THREAD_SAFE_ENABLE + + /* Release the thread safe mutex. */ + tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); +#endif + /* Return an error. */ + return(LX_ERROR); + } + + /* Get the logical sector number from spare bytes, and check if it matches the addressed sector number. */ + 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) + { +#ifdef LX_THREAD_SAFE_ENABLE + + /* Release the thread safe mutex. */ + tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); +#endif + /* Return successful completion. */ + return(LX_SUCCESS); + } } } else { - /* Set the status to success. */ - status = LX_SUCCESS; + /* Check if the logical sector is available. */ + if (logical_sector % nand_flash -> lx_nand_flash_pages_per_block < available_pages) + { + + /* Read a page. */ + status = (nand_flash -> lx_nand_flash_driver_pages_read)(block, logical_sector % nand_flash -> lx_nand_flash_pages_per_block, (UCHAR*)buffer, spare_buffer_ptr, 1); + + /* Check for an error from flash driver. */ + if (status) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, block, 0); + +#ifdef LX_THREAD_SAFE_ENABLE + + /* Release the thread safe mutex. */ + tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); +#endif + /* Return an error. */ + return(LX_ERROR); + } +#ifdef LX_THREAD_SAFE_ENABLE + + /* Release the thread safe mutex. */ + tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); +#endif + /* Return successful completion. */ + return(LX_SUCCESS); + } } } - else - { - - /* Sector hasn't been written. Simply fill the destination buffer with ones and return success. */ - /* Setup pointer to users buffer. */ - word_ptr = (ULONG *) buffer; - - /* Put all ones in he buffer. */ - for (i = 0; i < nand_flash -> lx_nand_flash_words_per_page; i++) - { - - /* Copy a word. */ - *word_ptr++ = LX_ALL_ONES; - } + /* Sector hasn't been written. Simply fill the destination buffer with ones and return success. */ - /* Set the status to success. */ - status = LX_SUCCESS; - } + /* Setup pointer to users buffer. */ + word_ptr = (ULONG *) buffer; + /* Put all ones in he buffer. */ + for (i = 0; i < nand_flash -> lx_nand_flash_words_per_page; i++) + { + + /* Copy a word. */ + *word_ptr++ = LX_ALL_ONES; + } + + /* Set the status to success. */ + status = LX_SUCCESS; + #ifdef LX_THREAD_SAFE_ENABLE /* Release the thread safe mutex. */ diff --git a/common/src/lx_nand_flash_sector_release.c b/common/src/lx_nand_flash_sector_release.c index 871cb93..14e02fc 100644 --- a/common/src/lx_nand_flash_sector_release.c +++ b/common/src/lx_nand_flash_sector_release.c @@ -40,10 +40,10 @@ /* FUNCTION RELEASE */ /* */ /* _lx_nand_flash_sector_release PORTABLE C */ -/* 6.1.7 */ +/* 6.x */ /* AUTHOR */ /* */ -/* William E. Lamie, Microsoft Corporation */ +/* Xiuwen Cai, Microsoft Corporation */ /* */ /* DESCRIPTION */ /* */ @@ -61,15 +61,19 @@ /* */ /* CALLS */ /* */ -/* _lx_nand_flash_driver_read Driver flash sector read */ -/* _lx_nand_flash_driver_write Driver flash sector write */ -/* _lx_nand_flash_driver_extra_bytes_get Get extra bytes from spare */ -/* _lx_nand_flash_driver_extra_bytes_set Set extra bytes in spare */ -/* _lx_nand_flash_block_obsoleted_check Check for block obsoleted */ -/* _lx_nand_flash_block_reclaim Reclaim one flash block */ -/* _lx_nand_flash_sector_mapping_cache_invalidate */ -/* Invalidate cache entry */ -/* _lx_nand_flash_logical_sector_find Find logical sector */ +/* _lx_nand_flash_block_find Find the mapped block */ +/* lx_nand_flash_driver_pages_read Read pages */ +/* _lx_nand_flash_block_allocate Allocate block */ +/* _lx_nand_flash_mapped_block_list_remove */ +/* Remove mapped block */ +/* _lx_nand_flash_data_page_copy Copy data pages */ +/* _lx_nand_flash_free_block_list_add Add free block to list */ +/* _lx_nand_flash_block_mapping_set Set block mapping */ +/* _lx_nand_flash_driver_block_erase Erase block */ +/* _lx_nand_flash_erase_count_set Set erase count */ +/* _lx_nand_flash_block_data_move Move block data */ +/* _lx_nand_flash_block_status_set Set block status */ +/* _lx_nand_flash_mapped_block_list_add Add mapped block to list */ /* _lx_nand_flash_system_error Internal system error handler */ /* tx_mutex_get Get thread protection */ /* tx_mutex_put Release thread protection */ @@ -82,23 +86,21 @@ /* */ /* DATE NAME DESCRIPTION */ /* */ -/* 05-19-2020 William E. Lamie Initial Version 6.0 */ -/* 09-30-2020 William E. Lamie Modified comment(s), */ -/* resulting in version 6.1 */ -/* 06-02-2021 Bhupendra Naphade Modified comment(s), */ -/* resulting in version 6.1.7 */ +/* xx-xx-xxxx Xiuwen Cai Initial Version 6.x */ /* */ /**************************************************************************/ UINT _lx_nand_flash_sector_release(LX_NAND_FLASH *nand_flash, ULONG logical_sector) { -LX_NAND_PAGE_EXTRA_INFO extra_info; -UINT status; -ULONG found_block; -ULONG found_page; -ULONG *block_word_ptr; -ULONG i; - +UINT status; +ULONG block; +USHORT block_status; +UCHAR *spare_buffer_ptr; +ULONG available_pages; +LONG page; +UINT release_sector = LX_FALSE; +ULONG new_block; +USHORT new_block_status; #ifdef LX_THREAD_SAFE_ENABLE @@ -109,38 +111,20 @@ ULONG i; /* Increment the number of release requests. */ nand_flash -> lx_nand_flash_diagnostic_sector_release_requests++; - /* See if we can find the logical sector in the current mapping. */ - _lx_nand_flash_logical_sector_find(nand_flash, logical_sector, LX_FALSE, &found_block, &found_page); - - /* Determine if the logical sector to page mapping was found. */ - if (found_page) + + /* See if we can find the sector in the current mapping. */ + status = _lx_nand_flash_block_find(nand_flash, logical_sector, &block, &block_status); + + /* Check return status. */ + if (status != LX_SUCCESS) { - - /* Yes, we were able to find the logical sector. */ - /* Determine if this sector is the current maximum sector. */ - if (nand_flash -> lx_nand_flash_max_mapped_sector == logical_sector) + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, block, 0); + + /* Determine if the error is fatal. */ + if (status != LX_NAND_ERROR_CORRECTED) { - - /* Yes, this is the maximum sector. Reduce the maximum, if possible. */ - if (logical_sector) - { - - /* Decrement the logical sector. */ - nand_flash -> lx_nand_flash_max_mapped_sector--; - } - } - - /* Read the extra information from the page. */ - status = _lx_nand_flash_driver_extra_bytes_get(nand_flash, found_block, found_page, (UCHAR *) &extra_info, sizeof(extra_info)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, found_block, found_page); - #ifdef LX_THREAD_SAFE_ENABLE /* Release the thread safe mutex. */ @@ -150,116 +134,339 @@ ULONG i; /* Return an error. */ return(LX_ERROR); } - - /* Mark this sector as invalid. */ - - /* Now clear bits 31 and 30, which indicates this sector is now obsoleted. */ - extra_info.lx_nand_page_extra_info_logical_sector = extra_info.lx_nand_page_extra_info_logical_sector & - ~(((ULONG) LX_NAND_PAGE_VALID) | ((ULONG) LX_NAND_PAGE_SUPERCEDED)); - - /* Write the value back to the flash to clear bits 31 & 30. */ - status = _lx_nand_flash_driver_extra_bytes_set(nand_flash, found_block, found_page, (UCHAR *) &extra_info, sizeof(extra_info)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, found_block, found_page); - -#ifdef LX_THREAD_SAFE_ENABLE - - /* Release the thread safe mutex. */ - tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); -#endif - - /* Return an error. */ - return(LX_ERROR); - } - - /* Increment the number of obsolete pages. */ - nand_flash -> lx_nand_flash_obsolete_pages++; - - /* Decrement the number of mapped pages. */ - nand_flash -> lx_nand_flash_mapped_pages--; - - /* Setup pointer to internal buffer. */ - block_word_ptr = nand_flash -> lx_nand_flash_page_buffer; - - /* Now read page 0 of the block, which has the erase count in the first 4 bytes. */ - status = _lx_nand_flash_driver_read(nand_flash, found_block, 0, block_word_ptr, (nand_flash -> lx_nand_flash_pages_per_block + 1)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, found_block, 0); - - /* Determine if the error is fatal. */ - if (status != LX_NAND_ERROR_CORRECTED) - { - -#ifdef LX_THREAD_SAFE_ENABLE - - /* Release the thread safe mutex. */ - tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); -#endif - - /* Return the error. */ - return(status); - } - } - -#ifndef LX_NAND_FLASH_MAPPING_LIST_UPDATE_DISABLE - - /* Determine if the mapping list in page 0 is valid. */ - if ((block_word_ptr[1] != LX_NAND_PAGE_FREE) && - (block_word_ptr[nand_flash -> lx_nand_flash_pages_per_block] == LX_NAND_PAGE_LIST_VALID)) - { - - /* Mark the entry as invalid. */ - block_word_ptr[found_page] &= ~LX_NAND_PAGE_VALID; - - /* Write the invalid entry. */ - status = _lx_nand_flash_driver_write(nand_flash, found_block, 0, block_word_ptr, (nand_flash -> lx_nand_flash_pages_per_block + 1)); - } -#endif - - /* Ensure the sector mapping cache no longer has this sector. */ - _lx_nand_flash_sector_mapping_cache_invalidate(nand_flash, logical_sector); - - /* Call routine to see if this block is completely obsoleted. If so, - we can reclaim it immediately. */ - _lx_nand_flash_block_obsoleted_check(nand_flash, found_block); - - /* Determine if there are less than two block's worth of free pages. */ - i = 0; - while (nand_flash -> lx_nand_flash_free_pages <= nand_flash -> lx_nand_flash_pages_per_block) - { - - /* Attempt to reclaim one block. */ - _lx_nand_flash_block_reclaim(nand_flash); - - /* Increment the block count. */ - i++; - - /* Have we exceeded the number of blocks in the system? */ - if (i >= nand_flash -> lx_nand_flash_total_blocks) - { - - /* Yes, break out of the loop. */ - break; - } - } } - else + + /* Determine if the block is mapped. */ + if (block != LX_NAND_BLOCK_UNMAPPED) { - /* Could not find the logical sector. */ - status = LX_SECTOR_NOT_FOUND; + /* Setup spare buffer pointer. */ + spare_buffer_ptr = (UCHAR*)nand_flash -> lx_nand_flash_page_buffer; + + /* Get available pages in this block. */ + 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; + + /* Determine if the pages are recorded sequentially. */ + if (block_status & LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL) + { + + /* Loop to search the logical page. */ + for (page = (LONG)available_pages - 1; page >= 0; page--) + { + + /* Read a page. */ + status = (nand_flash -> lx_nand_flash_driver_pages_read)(block, (ULONG)page, LX_NULL, spare_buffer_ptr, 1); + + /* Check for an error from flash driver. */ + if (status) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, block, 0); +#ifdef LX_THREAD_SAFE_ENABLE + + /* Release the thread safe mutex. */ + tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); +#endif + + /* Return an error. */ + return(LX_ERROR); + } + + /* Get the logical sector number from spare bytes, and check if it matches the addressed sector number. */ + 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) + { + + /* Make sure the sector is not released. */ + 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)) + { + + /* Set release sector flag. */ + release_sector = LX_TRUE; + } + } + } + } + else + { + + /* Check if the logical sector is available. */ + if (logical_sector % nand_flash -> lx_nand_flash_pages_per_block < available_pages) + { + + /* Set release sector flag. */ + release_sector = LX_TRUE; + } + } + + /* Determine if the sector needs to be released. */ + if (release_sector) + { + + /* Check if the block is full. */ + if (block_status & LX_NAND_BLOCK_STATUS_FULL) + { + + /* Allocate a new block. */ + status = _lx_nand_flash_block_allocate(nand_flash, &new_block); + + /* Check return status. */ + if (status != LX_SUCCESS) + { + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, new_block, 0); +#ifdef LX_THREAD_SAFE_ENABLE + + /* Release the thread safe mutex. */ + tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); +#endif + + /* Return an error. */ + return(LX_ERROR); + + } + + /* Set new block status to allocated. */ + new_block_status = LX_NAND_BLOCK_STATUS_ALLOCATED; + + /* Remove the old block from mapped block list. */ + _lx_nand_flash_mapped_block_list_remove(nand_flash, logical_sector / nand_flash -> lx_nand_flash_pages_per_block); + + /* Copy valid sector to new block. */ + 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)); + + /* Check for an error from flash driver. */ + if (status) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, new_block, 0); +#ifdef LX_THREAD_SAFE_ENABLE + + /* Release the thread safe mutex. */ + tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); +#endif + + /* Return an error. */ + return(LX_ERROR); + } + + /* Determine if there are sectors after the addressed sector need to be copied. */ + if (logical_sector % nand_flash -> lx_nand_flash_pages_per_block < nand_flash -> lx_nand_flash_pages_per_block - 1) + { + + /* Copy valid sector to new block. */ + 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)); + + /* Check for an error from flash driver. */ + if (status) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, new_block, 0); +#ifdef LX_THREAD_SAFE_ENABLE + + /* Release the thread safe mutex. */ + tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); +#endif + + /* Return an error. */ + return(LX_ERROR); + } + } + + /* Check new block status to see if there is valid pages in the block. */ + if ((new_block_status & LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK) == 0) + { + + /* Add the block to free block list. */ + _lx_nand_flash_free_block_list_add(nand_flash, new_block); + + /* Set new block to unmapped. */ + new_block = LX_NAND_BLOCK_UNMAPPED; + } + else + { + + /* Set new block status. */ + status = _lx_nand_flash_block_status_set(nand_flash, new_block, new_block_status); + + /* Check for an error from flash driver. */ + if (status) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, block, 0); +#ifdef LX_THREAD_SAFE_ENABLE + + /* Release the thread safe mutex. */ + tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); +#endif + + /* Return an error. */ + return(LX_ERROR); + } + } + + /* Update block mapping. */ + _lx_nand_flash_block_mapping_set(nand_flash, logical_sector, new_block); + + /* Erase old block. */ + 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); + + /* Check for an error from flash driver. */ + if (status) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, block, 0); +#ifdef LX_THREAD_SAFE_ENABLE + + /* Release the thread safe mutex. */ + tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); +#endif + + /* Return an error. */ + return(LX_ERROR); + } + + /* Update erase count for the old block. */ + status = _lx_nand_flash_erase_count_set(nand_flash, block, (UCHAR)(nand_flash -> lx_nand_flash_erase_count_table[block] + 1)); + + /* Check for an error from flash driver. */ + if (status) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, block, 0); +#ifdef LX_THREAD_SAFE_ENABLE + + /* Release the thread safe mutex. */ + tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); +#endif + + /* Return an error. */ + return(LX_ERROR); + } + + /* Check if the block has too many erases. */ + if (nand_flash -> lx_nand_flash_erase_count_table[block] > LX_NAND_FLASH_MAX_ERASE_COUNT_DELTA) + { + + /* Move data from less worn block. */ + _lx_nand_flash_block_data_move(nand_flash, block); + } + else + { + + /* Set the block status to free. */ + status = _lx_nand_flash_block_status_set(nand_flash, block, LX_NAND_BLOCK_STATUS_FREE); + + /* Check for an error from flash driver. */ + if (status) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, block, 0); +#ifdef LX_THREAD_SAFE_ENABLE + + /* Release the thread safe mutex. */ + tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); +#endif + + /* Return an error. */ + return(LX_ERROR); + } + + /* Add the block to free block list. */ + _lx_nand_flash_free_block_list_add(nand_flash, block); + } + + /* Check if there is valid pages in the new block. */ + if ((new_block_status & LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK) != 0) + { + + /* Add the new block to mapped block list. */ + _lx_nand_flash_mapped_block_list_add(nand_flash, logical_sector / nand_flash -> lx_nand_flash_pages_per_block); + } + } + else + { + + /* Set page buffer to all 0xFF bytes. */ + 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); + + /* Setup spare buffer pointer. */ + spare_buffer_ptr = nand_flash -> lx_nand_flash_page_buffer + nand_flash -> lx_nand_flash_bytes_per_page; + + /* Check if there is enough spare data for metadata block number. */ + if (nand_flash -> lx_nand_flash_spare_data2_length >= sizeof(USHORT)) + { + + /* Save metadata block number in spare bytes. */ + LX_UTILITY_SHORT_SET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data2_offset], nand_flash -> lx_nand_flash_metadata_block_number); + } + + /* Set page type and sector address. */ + LX_UTILITY_LONG_SET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset], LX_NAND_PAGE_TYPE_USER_DATA_RELEASED | logical_sector); + + /* Write the page. */ + status = (nand_flash -> lx_nand_flash_driver_pages_write)(block, available_pages, (UCHAR*)nand_flash -> lx_nand_flash_page_buffer, spare_buffer_ptr, 1); + + /* Check for an error from flash driver. */ + if (status) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, block, 0); +#ifdef LX_THREAD_SAFE_ENABLE + + /* Release the thread safe mutex. */ + tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); +#endif + + /* Return an error. */ + return(LX_ERROR); + } + + /* Increase available pages count. */ + available_pages++; + + /* Check if available pages count reaches total pages per block. */ + if (available_pages == nand_flash -> lx_nand_flash_pages_per_block) + { + + /* Set block full status flag. */ + block_status |= LX_NAND_BLOCK_STATUS_FULL; + } + + /* Build block status word. */ + block_status = (USHORT)(available_pages | (block_status & ~LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK)); + + /* Set non sequential status flag. */ + block_status |= LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL; + + /* Set block status. */ + status = _lx_nand_flash_block_status_set(nand_flash, block, block_status); + + /* Check for an error from flash driver. */ + if (status) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, block, 0); +#ifdef LX_THREAD_SAFE_ENABLE + + /* Release the thread safe mutex. */ + tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); +#endif + + /* Return an error. */ + return(LX_ERROR); + } + } + } } - #ifdef LX_THREAD_SAFE_ENABLE /* Release the thread safe mutex. */ diff --git a/common/src/lx_nand_flash_sector_write.c b/common/src/lx_nand_flash_sector_write.c index e6e6d0f..e31ccd5 100644 --- a/common/src/lx_nand_flash_sector_write.c +++ b/common/src/lx_nand_flash_sector_write.c @@ -40,10 +40,10 @@ /* FUNCTION RELEASE */ /* */ /* _lx_nand_flash_sector_write PORTABLE C */ -/* 6.1.7 */ +/* 6.x */ /* AUTHOR */ /* */ -/* William E. Lamie, Microsoft Corporation */ +/* Xiuwen Cai, Microsoft Corporation */ /* */ /* DESCRIPTION */ /* */ @@ -63,18 +63,19 @@ /* */ /* CALLS */ /* */ -/* _lx_nand_flash_driver_read Driver flash sector read */ -/* _lx_nand_flash_driver_write Driver flash sector write */ -/* _lx_nand_flash_driver_extra_bytes_get Get extra bytes from spare */ -/* _lx_nand_flash_driver_extra_bytes_set Set extra bytes in spare */ -/* _lx_nand_flash_block_full_update Update page 0 with list of */ -/* mapped pages */ -/* _lx_nand_flash_block_obsoleted_check Check for block obsoleted */ -/* _lx_nand_flash_block_reclaim Reclaim one flash block */ -/* _lx_nand_flash_logical_sector_find Find logical sector */ -/* _lx_nand_flash_physical_page_allocate Allocate new page */ -/* _lx_nand_flash_sector_mapping_cache_invalidate */ -/* Invalidate cache entry */ +/* _lx_nand_flash_block_find Find the mapped block */ +/* _lx_nand_flash_block_allocate Allocate block */ +/* _lx_nand_flash_mapped_block_list_remove */ +/* Remove mapped block */ +/* _lx_nand_flash_data_page_copy Copy data pages */ +/* _lx_nand_flash_free_block_list_add Add free block to list */ +/* _lx_nand_flash_block_mapping_set Set block mapping */ +/* lx_nand_flash_driver_pages_write Write pages */ +/* _lx_nand_flash_block_status_set Set block status */ +/* _lx_nand_flash_driver_block_erase Erase block */ +/* _lx_nand_flash_erase_count_set Set erase count */ +/* _lx_nand_flash_block_data_move Move block data */ +/* _lx_nand_flash_mapped_block_list_add Add mapped block to list */ /* _lx_nand_flash_system_error Internal system error handler */ /* tx_mutex_get Get thread protection */ /* tx_mutex_put Release thread protection */ @@ -87,30 +88,21 @@ /* */ /* DATE NAME DESCRIPTION */ /* */ -/* 05-19-2020 William E. Lamie Initial Version 6.0 */ -/* 09-30-2020 William E. Lamie Modified comment(s), */ -/* resulting in version 6.1 */ -/* 06-02-2021 Bhupendra Naphade Modified comment(s), */ -/* resulting in version 6.1.7 */ +/* xx-xx-xxxx Xiuwen Cai Initial Version 6.x */ /* */ /**************************************************************************/ UINT _lx_nand_flash_sector_write(LX_NAND_FLASH *nand_flash, ULONG logical_sector, VOID *buffer) { -LX_NAND_PAGE_EXTRA_INFO old_extra_info; -LX_NAND_PAGE_EXTRA_INFO new_extra_info; -ULONG old_block; -ULONG old_page; -ULONG new_block; -ULONG new_page; -ULONG new_erase_count; -ULONG i; -#ifndef LX_NAND_FLASH_DIRECT_MAPPING_CACHE -LX_NAND_SECTOR_MAPPING_CACHE_ENTRY *sector_mapping_cache_entry_ptr; -#endif UINT status; -ULONG *block_word_ptr; - +ULONG block; +ULONG new_block; +ULONG page; +USHORT block_status = 0; +USHORT new_block_status = LX_NAND_BLOCK_STATUS_ALLOCATED; +UCHAR *spare_buffer_ptr; +UINT update_mapping = LX_FALSE; +UINT copy_block = LX_FALSE; #ifdef LX_THREAD_SAFE_ENABLE @@ -118,62 +110,22 @@ ULONG *block_word_ptr; tx_mutex_get(&nand_flash -> lx_nand_flash_mutex, TX_WAIT_FOREVER); #endif - /* Determine if there are less than two block's worth of free pages. */ - i = 0; - while (nand_flash -> lx_nand_flash_free_pages <= nand_flash -> lx_nand_flash_pages_per_block) - { - - /* Attempt to reclaim one block. */ - _lx_nand_flash_block_reclaim(nand_flash); - - /* Increment the block count. */ - i++; - - /* Have we exceeded the number of blocks in the system? */ - if (i >= nand_flash -> lx_nand_flash_total_blocks) - { - - /* Yes, break out of the loop. */ - break; - } - } - /* Increment the number of write requests. */ nand_flash -> lx_nand_flash_diagnostic_sector_write_requests++; /* See if we can find the logical sector in the current mapping. */ - _lx_nand_flash_logical_sector_find(nand_flash, logical_sector, LX_FALSE, &old_block, &old_page); + status = _lx_nand_flash_block_find(nand_flash, logical_sector, &block, &block_status); - /* Allocate a new page for this write. */ - _lx_nand_flash_physical_page_allocate(nand_flash, &new_block, &new_page, &new_erase_count); - - /* Determine if the new page allocation was successful. */ - if (new_page) + /* Check return status. */ + if(status != LX_SUCCESS) { - - /* Yes, we were able to allocate a new page. */ - /* Determine if this is the new maximum mapped sector. */ - if (logical_sector > nand_flash -> lx_nand_flash_max_mapped_sector) + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, block, 0); + + /* Determine if the error is fatal. */ + if (status != LX_NAND_ERROR_CORRECTED) { - - /* Remember this maximum mapped sector. */ - nand_flash -> lx_nand_flash_max_mapped_sector = logical_sector; - } - - /* Update the number of free pages. */ - nand_flash -> lx_nand_flash_free_pages--; - - /* Write the logical sector data to the new page. */ - status = _lx_nand_flash_driver_write(nand_flash, new_block, new_page, buffer, nand_flash -> lx_nand_flash_words_per_page); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, new_block, new_page); - #ifdef LX_THREAD_SAFE_ENABLE /* Release the thread safe mutex. */ @@ -183,44 +135,38 @@ ULONG *block_word_ptr; /* Return an error. */ return(LX_ERROR); } + } - /* Determine if there was an old mapping. */ - if (old_page) + /* Check if block is unmapped or block is full. */ + if (block == LX_NAND_BLOCK_UNMAPPED || block_status & LX_NAND_BLOCK_STATUS_FULL) + { + + /* Allocate a new block. */ + status = _lx_nand_flash_block_allocate(nand_flash, &new_block); + + /* Check if there is no blocks. */ + if (status == LX_NO_BLOCKS) { - - /* Read the extra info of the old page. */ - status = _lx_nand_flash_driver_extra_bytes_get(nand_flash, old_block, old_page, (UCHAR *) &old_extra_info, sizeof(old_extra_info)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, old_block, old_page); - #ifdef LX_THREAD_SAFE_ENABLE - /* Release the thread safe mutex. */ - tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); + /* Release the thread safe mutex. */ + tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); #endif - /* Return an error. */ - return(LX_ERROR); - } - - /* Clear bit 30, which indicates this sector is superceded. */ - old_extra_info.lx_nand_page_extra_info_logical_sector = old_extra_info.lx_nand_page_extra_info_logical_sector & (~((ULONG) LX_NAND_PAGE_SUPERCEDED)); + /* Return error. */ + return(status); + } - /* Write the extra info to old page. */ - status = _lx_nand_flash_driver_extra_bytes_set(nand_flash, old_block, old_page, (UCHAR *) &old_extra_info, sizeof(old_extra_info)); - - /* Check for an error from flash driver. */ - if (status) + /* Check return status. */ + else if (status != LX_SUCCESS) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, new_block, 0); + + /* Determine if the error is fatal. */ + if (status != LX_NAND_ERROR_CORRECTED) { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, old_block, old_page); - #ifdef LX_THREAD_SAFE_ENABLE /* Release the thread safe mutex. */ @@ -232,221 +178,246 @@ ULONG *block_word_ptr; } } - /* Now build the new mapping entry - with the not valid bit set initially. */ - new_extra_info.lx_nand_page_extra_info_logical_sector = ((ULONG) LX_NAND_PAGE_VALID) | ((ULONG) LX_NAND_PAGE_SUPERCEDED) | ((ULONG) LX_NAND_PAGE_MAPPING_NOT_VALID) | logical_sector; - - /* Write out the new mapping entry. */ - status = _lx_nand_flash_driver_extra_bytes_set(nand_flash, new_block, new_page, (UCHAR *) &new_extra_info, sizeof(new_extra_info)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, new_block, new_page); - -#ifdef LX_THREAD_SAFE_ENABLE - - /* Release the thread safe mutex. */ - tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); -#endif - - /* Return an error. */ - return(LX_ERROR); - } - - /* Now clear the not valid bit to make this sector mapping valid. This is done because the writing of the extra bytes itself can - be interrupted and we need to make sure this can be detected when the flash is opened again. */ - new_extra_info.lx_nand_page_extra_info_logical_sector = new_extra_info.lx_nand_page_extra_info_logical_sector & ~((ULONG) LX_NAND_PAGE_MAPPING_NOT_VALID); - - /* Clear the not valid bit. */ - status = _lx_nand_flash_driver_extra_bytes_set(nand_flash, new_block, new_page, (UCHAR *) &new_extra_info, sizeof(new_extra_info)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, new_block, new_page); - -#ifdef LX_THREAD_SAFE_ENABLE - - /* Release the thread safe mutex. */ - tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); -#endif - - /* Return an error. */ - return(LX_ERROR); - } - - - /* Increment the number of mapped sectors. */ - nand_flash -> lx_nand_flash_mapped_pages++; - - /* Was there a previously mapped sector? */ - if (old_page) - { - - /* Now clear bit 31, which indicates this sector is now obsoleted. */ - old_extra_info.lx_nand_page_extra_info_logical_sector = old_extra_info.lx_nand_page_extra_info_logical_sector & ~((ULONG) LX_NAND_PAGE_VALID); - - /* Write the value back to the flash to clear bit 31. */ - status = _lx_nand_flash_driver_extra_bytes_set(nand_flash, old_block, old_page, (UCHAR *) &old_extra_info, sizeof(old_extra_info)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, old_block, old_page); - -#ifdef LX_THREAD_SAFE_ENABLE - - /* Release the thread safe mutex. */ - tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); -#endif - - /* Return an error. */ - return(LX_ERROR); - } - - /* Setup pointer to internal buffer. */ - block_word_ptr = nand_flash -> lx_nand_flash_page_buffer; - - /* Now read page 0 of the block, which has the erase count in the first 4 bytes. */ - status = _lx_nand_flash_driver_read(nand_flash, old_block, 0, block_word_ptr, (nand_flash -> lx_nand_flash_pages_per_block + 1)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, old_block, 0); - - /* Determine if the error is fatal. */ - if (status != LX_NAND_ERROR_CORRECTED) - { - -#ifdef LX_THREAD_SAFE_ENABLE - - /* Release the thread safe mutex. */ - tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); -#endif - - /* Return the error. */ - return(status); - } - } - -#ifndef LX_NAND_FLASH_MAPPING_LIST_UPDATE_DISABLE - - /* Determine if there is a valid mapping list. */ - if ((block_word_ptr[1] != LX_NAND_PAGE_FREE) && - (block_word_ptr[nand_flash -> lx_nand_flash_pages_per_block] == LX_NAND_PAGE_LIST_VALID)) - { - - /* Mark the entry as invalid. */ - block_word_ptr[old_page] &= ~LX_NAND_PAGE_VALID; - - /* Invalidate the page. */ - status = _lx_nand_flash_driver_write(nand_flash, old_block, 0, block_word_ptr, (nand_flash -> lx_nand_flash_pages_per_block + 1)); - } -#endif - - /* Increment the number of obsolete pages. */ - nand_flash -> lx_nand_flash_obsolete_pages++; - - /* Decrement the number of mapped pages. */ - nand_flash -> lx_nand_flash_mapped_pages--; - - /* Invalidate the old sector mapping cache entry. */ - _lx_nand_flash_sector_mapping_cache_invalidate(nand_flash, logical_sector); - - /* Call routine to see if this block is completely obsoleted. If so, - we can reclaim it immediately. */ - _lx_nand_flash_block_obsoleted_check(nand_flash, old_block); - } - - /* Read the extra info of the old page. */ - status = _lx_nand_flash_driver_extra_bytes_get(nand_flash, new_block, new_page, (UCHAR *) &new_extra_info, sizeof(new_extra_info)); - - /* Check for an error from flash driver. */ - if (status) - { - - /* Call system error handler. */ - _lx_nand_flash_system_error(nand_flash, status, old_block, old_page); - -#ifdef LX_THREAD_SAFE_ENABLE - - /* Release the thread safe mutex. */ - tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); -#endif - - /* Return an error. */ - return(LX_ERROR); - } - - /* Check to see if the logical sector is still mapped to the same block/page. */ - if (((new_extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_LOGICAL_SECTOR_MASK) == logical_sector) && - (new_extra_info.lx_nand_page_extra_info_logical_sector & ((ULONG) LX_NAND_PAGE_VALID))) + /* Check if the block is full. */ + if (block_status & LX_NAND_BLOCK_STATUS_FULL) { - /* Determine if the new page is the last page of the block. */ - if (new_page == (nand_flash -> lx_nand_flash_pages_per_block - 1)) - { - - - /* Yes, we need to update page 0 of the block with the list of mapped - pages for this block. */ - _lx_nand_flash_block_full_update(nand_flash, new_block, new_erase_count); - } - - /* Determine if the logical sector mapping cache is enabled. */ - if (nand_flash -> lx_nand_flash_sector_mapping_cache_enabled) - { - - /* Yes, sector mapping cache is enabled, place this logical sector mapping information in the cache. */ - -#ifndef LX_NAND_FLASH_DIRECT_MAPPING_CACHE - - /* Calculate the starting index of the sector mapping cache for this sector entry. */ - i = (logical_sector & LX_NAND_SECTOR_MAPPING_CACHE_HASH_MASK) * LX_NAND_SECTOR_MAPPING_CACHE_DEPTH; - - /* Build a pointer to the cache entry. */ - sector_mapping_cache_entry_ptr = &nand_flash -> lx_nand_flash_sector_mapping_cache[i]; - - /* Move all the cache entries down so the oldest is at the bottom. */ - *(sector_mapping_cache_entry_ptr + 3) = *(sector_mapping_cache_entry_ptr + 2); - *(sector_mapping_cache_entry_ptr + 2) = *(sector_mapping_cache_entry_ptr + 1); - *(sector_mapping_cache_entry_ptr + 1) = *(sector_mapping_cache_entry_ptr); - - /* Setup the new logical sector information in the cache. */ - sector_mapping_cache_entry_ptr -> lx_nand_sector_mapping_cache_logical_sector = (logical_sector | LX_NAND_SECTOR_MAPPING_CACHE_ENTRY_VALID); - sector_mapping_cache_entry_ptr -> lx_nand_sector_mapping_cache_block = (USHORT) new_block; - sector_mapping_cache_entry_ptr -> lx_nand_sector_mapping_cache_page = (USHORT) new_page; -#else - - /* Determine if this logical sector fits in the logical sector cache mapping. */ - if (logical_sector < LX_NAND_SECTOR_MAPPING_CACHE_SIZE) - { - - /* Yes, store the logical sector to block/page mapping in the cache. */ - nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_block = (USHORT) new_block; - nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_page = (USHORT) new_page; - } -#endif - } + /* Set copy block flag. */ + copy_block = LX_TRUE; } - /* Indicate the write was successful. */ - status = LX_SUCCESS; + /* Set update mapping flag. */ + update_mapping = LX_TRUE; } else { + + /* Set new block to the same as old block. */ + new_block = block; + new_block_status = block_status; + } - /* Indicate the write was unsuccessful. */ - status = LX_NO_SECTORS; + /* Check if copy block flag is set. */ + if (copy_block) + { + + /* Remove the old block from mapped block list. */ + _lx_nand_flash_mapped_block_list_remove(nand_flash, logical_sector / nand_flash -> lx_nand_flash_pages_per_block); + + /* Copy valid sector to new block. */ + 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)); + + /* Check for an error from flash driver. */ + if (status) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, block, 0); +#ifdef LX_THREAD_SAFE_ENABLE + + /* Release the thread safe mutex. */ + tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); +#endif + + /* Return an error. */ + return(LX_ERROR); + } + } + + /* Check if update mapping flag is set. */ + if (update_mapping) + { + + /* Update block mapping. */ + _lx_nand_flash_block_mapping_set(nand_flash, logical_sector, new_block); + } + + /* Setup spare buffer pointer. */ + spare_buffer_ptr = nand_flash -> lx_nand_flash_page_buffer; + + /* Set spare buffer to all 0xFF bytes. */ + LX_MEMSET(spare_buffer_ptr, 0xFF, nand_flash -> lx_nand_flash_spare_total_length); + + /* Check if there is enough spare data for metadata block number. */ + if (nand_flash -> lx_nand_flash_spare_data2_length >= sizeof(USHORT)) + { + + /* Save metadata block number in spare bytes. */ + LX_UTILITY_SHORT_SET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data2_offset], nand_flash -> lx_nand_flash_metadata_block_number); + } + + /* Set page type and sector address. */ + LX_UTILITY_LONG_SET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset], LX_NAND_PAGE_TYPE_USER_DATA | logical_sector); + + /* Get page to write. */ + page = new_block_status & LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK; + + /* Write the page. */ + status = (nand_flash -> lx_nand_flash_driver_pages_write)(new_block, page, (UCHAR*)buffer, spare_buffer_ptr, 1); + + /* Check for an error from flash driver. */ + if (status) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, new_block, 0); +#ifdef LX_THREAD_SAFE_ENABLE + + /* Release the thread safe mutex. */ + tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); +#endif + + /* Return an error. */ + return(LX_ERROR); + } + + /* Determine if the sector number is sequential. */ + if ((new_block_status & LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK) != (logical_sector % nand_flash -> lx_nand_flash_pages_per_block)) + { + + /* Set non sequential status flag. */ + new_block_status |= LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL; + } + + /* Increase page number. */ + page++; + + /* Check if page number reaches total pages per block. */ + if (page == nand_flash -> lx_nand_flash_pages_per_block) + { + + /* Set block full status flag. */ + new_block_status |= LX_NAND_BLOCK_STATUS_FULL; + } + + /* Build block status word. */ + new_block_status = (USHORT)(page | (new_block_status & ~LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK)); + + /* Determine if there are sectors after the addressed sector need to be copied. */ + if (copy_block && ((logical_sector % nand_flash -> lx_nand_flash_pages_per_block) < (nand_flash -> lx_nand_flash_pages_per_block - 1))) + { + + /* Copy valid sector to new block. */ + 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)); + + /* Check for an error from flash driver. */ + if (status) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, block, 0); +#ifdef LX_THREAD_SAFE_ENABLE + + /* Release the thread safe mutex. */ + tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); +#endif + + /* Return an error. */ + return(LX_ERROR); + } + } + + /* Set new block status. */ + status = _lx_nand_flash_block_status_set(nand_flash, new_block, new_block_status); + + /* Check for an error from flash driver. */ + if (status) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, new_block, 0); +#ifdef LX_THREAD_SAFE_ENABLE + + /* Release the thread safe mutex. */ + tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); +#endif + + /* Return an error. */ + return(LX_ERROR); + } + + /* Check if copy block flag is set. */ + if (copy_block) + { + + /* Erase old block. */ + 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); + + /* Check for an error from flash driver. */ + if (status) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, block, 0); +#ifdef LX_THREAD_SAFE_ENABLE + + /* Release the thread safe mutex. */ + tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); +#endif + + /* Return an error. */ + return(LX_ERROR); + } + + /* Update erase count for the old block. */ + status = _lx_nand_flash_erase_count_set(nand_flash, block, (UCHAR)(nand_flash -> lx_nand_flash_erase_count_table[block] + 1)); + + /* Check for an error from flash driver. */ + if (status) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, block, 0); +#ifdef LX_THREAD_SAFE_ENABLE + + /* Release the thread safe mutex. */ + tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); +#endif + + /* Return an error. */ + return(LX_ERROR); + } + + /* Check if the block has too many erases. */ + if (nand_flash -> lx_nand_flash_erase_count_table[block] > LX_NAND_FLASH_MAX_ERASE_COUNT_DELTA) + { + + /* Move data from less worn block. */ + _lx_nand_flash_block_data_move(nand_flash, block); + } + else + { + + /* Set the block status to free. */ + status = _lx_nand_flash_block_status_set(nand_flash, block, LX_NAND_BLOCK_STATUS_FREE); + + /* Check for an error from flash driver. */ + if (status) + { + + /* Call system error handler. */ + _lx_nand_flash_system_error(nand_flash, status, block, 0); +#ifdef LX_THREAD_SAFE_ENABLE + + /* Release the thread safe mutex. */ + tx_mutex_put(&nand_flash -> lx_nand_flash_mutex); +#endif + + /* Return an error. */ + return(LX_ERROR); + } + + /* Add the block to free block list. */ + _lx_nand_flash_free_block_list_add(nand_flash, block); + } + } + + /* Check if update mapping flag is set. */ + if (update_mapping) + { + + /* Add the new block to mapped block list. */ + _lx_nand_flash_mapped_block_list_add(nand_flash, logical_sector / nand_flash -> lx_nand_flash_pages_per_block); } #ifdef LX_THREAD_SAFE_ENABLE diff --git a/common/src/lx_nand_flash_sectors_read.c b/common/src/lx_nand_flash_sectors_read.c new file mode 100644 index 0000000..2ac356f --- /dev/null +++ b/common/src/lx_nand_flash_sectors_read.c @@ -0,0 +1,106 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** LevelX Component */ +/** */ +/** NAND Flash */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define LX_SOURCE_CODE + + +/* Disable ThreadX error checking. */ + +#ifndef LX_DISABLE_ERROR_CHECKING +#define LX_DISABLE_ERROR_CHECKING +#endif + + +/* Include necessary system files. */ + +#include "lx_api.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _lx_nand_flash_sectors_read PORTABLE C */ +/* 6.x */ +/* AUTHOR */ +/* */ +/* Xiuwen Cai, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function reads multiple logical sectors from NAND flash. */ +/* */ +/* INPUT */ +/* */ +/* nand_flash NAND flash instance */ +/* logical_sector Logical sector number */ +/* buffer Pointer to buffer to read into*/ +/* (the size is number of */ +/* bytes in a page) */ +/* sector_count Number of sector to read */ +/* */ +/* OUTPUT */ +/* */ +/* return status */ +/* */ +/* CALLS */ +/* */ +/* _lx_nand_flash_sector_read Read a sector */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* xx-xx-xxxx Xiuwen Cai Initial Version 6.x */ +/* */ +/**************************************************************************/ +UINT _lx_nand_flash_sectors_read(LX_NAND_FLASH *nand_flash, ULONG logical_sector, VOID *buffer, ULONG sector_count) +{ + +UINT status = LX_SUCCESS; +UINT i; + + + /* Loop to read all the sectors. */ + for (i = 0; i < sector_count; i++) + { + + /* Read one sector. */ + status = _lx_nand_flash_sector_read(nand_flash, logical_sector + i, ((UCHAR*)buffer) + i * nand_flash -> lx_nand_flash_bytes_per_page); + + /* Check return status. */ + if (status) + { + + /* Error, break the loop. */ + break; + } + } + + /* Return status. */ + return(status); +} + diff --git a/common/src/lx_nand_flash_sectors_release.c b/common/src/lx_nand_flash_sectors_release.c new file mode 100644 index 0000000..402ed47 --- /dev/null +++ b/common/src/lx_nand_flash_sectors_release.c @@ -0,0 +1,104 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** LevelX Component */ +/** */ +/** NAND Flash */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define LX_SOURCE_CODE + + +/* Disable ThreadX error checking. */ + +#ifndef LX_DISABLE_ERROR_CHECKING +#define LX_DISABLE_ERROR_CHECKING +#endif + + +/* Include necessary system files. */ + +#include "lx_api.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _lx_nand_flash_sectors_release PORTABLE C */ +/* 6.x */ +/* AUTHOR */ +/* */ +/* Xiuwen Cai, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function releases multiple logical sectors from being managed */ +/* in the NAND flash. */ +/* */ +/* INPUT */ +/* */ +/* nand_flash NAND flash instance */ +/* logical_sector Logical sector number */ +/* sector_count Number of sector to release */ +/* */ +/* OUTPUT */ +/* */ +/* return status */ +/* */ +/* CALLS */ +/* */ +/* _lx_nand_flash_sector_release Release one sector */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* xx-xx-xxxx Xiuwen Cai Initial Version 6.x */ +/* */ +/**************************************************************************/ +UINT _lx_nand_flash_sectors_release(LX_NAND_FLASH *nand_flash, ULONG logical_sector, ULONG sector_count) +{ + +UINT status = LX_SUCCESS; +UINT i; + + + /* Loop to release all the sectors. */ + for (i = 0; i < sector_count; i++) + { + + /* Release one sector. */ + status = _lx_nand_flash_sector_release(nand_flash, logical_sector + i); + + /* Check return status. */ + if (status) + { + + /* Error, break the loop. */ + break; + } + } + + /* Return status. */ + return(status); +} + diff --git a/common/src/lx_nand_flash_sectors_write.c b/common/src/lx_nand_flash_sectors_write.c new file mode 100644 index 0000000..c0c59d9 --- /dev/null +++ b/common/src/lx_nand_flash_sectors_write.c @@ -0,0 +1,107 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** LevelX Component */ +/** */ +/** NAND Flash */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define LX_SOURCE_CODE + + +/* Disable ThreadX error checking. */ + +#ifndef LX_DISABLE_ERROR_CHECKING +#define LX_DISABLE_ERROR_CHECKING +#endif + + +/* Include necessary system files. */ + +#include "lx_api.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _lx_nand_flash_sectors_write PORTABLE C */ +/* 6.x */ +/* AUTHOR */ +/* */ +/* Xiuwen Cai, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function writes multiple logical sectors to the NAND flash. */ +/* */ +/* INPUT */ +/* */ +/* nand_flash NAND flash instance */ +/* logical_sector Logical sector number */ +/* buffer Pointer to buffer to write */ +/* (the size is number of */ +/* bytes in a page) */ +/* sector_count Number of sector to write */ +/* */ +/* OUTPUT */ +/* */ +/* return status */ +/* */ +/* CALLS */ +/* */ +/* _lx_nand_flash_sector_write Write one sector */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* xx-xx-xxxx Xiuwen Cai Initial Version 6.x */ +/* */ +/**************************************************************************/ +UINT _lx_nand_flash_sectors_write(LX_NAND_FLASH *nand_flash, ULONG logical_sector, VOID *buffer, ULONG sector_count) +{ + +UINT status = LX_SUCCESS; +UINT i; + + + /* Loop to write all the sectors. */ + for (i = 0; i < sector_count; i++) + { + + /* Write one sector. */ + status = _lx_nand_flash_sector_write(nand_flash, logical_sector + i, ((UCHAR*)buffer) + i * nand_flash -> lx_nand_flash_bytes_per_page); + + /* Check return status. */ + if (status) + { + + /* Error, break the loop. */ + break; + } + } + + /* Return status. */ + return(status); +} + + diff --git a/common/src/lx_nand_flash_simulator.c b/common/src/lx_nand_flash_simulator.c index 140fc10..40f9cf0 100644 --- a/common/src/lx_nand_flash_simulator.c +++ b/common/src/lx_nand_flash_simulator.c @@ -27,15 +27,21 @@ /* Define constants for the NAND flash simulation. */ -#define TOTAL_BLOCKS 8 -#define PHYSICAL_PAGES_PER_BLOCK 16 /* Min value of 2 */ -#define BYTES_PER_PHYSICAL_PAGE 2048 /* 2048 bytes per page */ -#define WORDS_PER_PHYSICAL_PAGE 2048/4 /* Words per page */ -#define SPARE_BYTES_PER_PAGE 64 /* 64 "spare" bytes per page */ +#define TOTAL_BLOCKS 1024 +#define PHYSICAL_PAGES_PER_BLOCK 256 /* Min value of 2 */ +#define BYTES_PER_PHYSICAL_PAGE 512 /* 512 bytes per page */ +#define WORDS_PER_PHYSICAL_PAGE 512 / 4 /* Words per page */ +#define SPARE_BYTES_PER_PAGE 16 /* 16 "spare" bytes per page */ /* For 2048 byte block spare area: */ #define BAD_BLOCK_POSITION 0 /* 0 is the bad block byte postion */ -#define EXTRA_BYTE_POSITION 2 /* 2 is the extra bytes starting byte postion */ -#define ECC_BYTE_POSITION 40 /* 40 is the ECC starting byte position */ +#define EXTRA_BYTE_POSITION 0 /* 0 is the extra bytes starting byte postion */ +#define ECC_BYTE_POSITION 8 /* 8 is the ECC starting byte position */ +#define SPARE_DATA1_OFFSET 4 +#define SPARE_DATA1_LENGTH 4 +#define SPARE_DATA2_OFFSET 2 +#define SPARE_DATA2_LENGTH 2 + + /* Definition of the spare area is relative to the block size of the NAND part and perhaps manufactures of the NAND part. Here are some common definitions: @@ -111,7 +117,10 @@ UINT _lx_nand_flash_simulator_extra_bytes_get(ULONG block, ULONG page, UCHAR *d UINT _lx_nand_flash_simulator_extra_bytes_set(ULONG block, ULONG page, UCHAR *source, UINT size); UINT _lx_nand_flash_simulator_system_error(UINT error_code, ULONG block, ULONG page); - +UINT _lx_nand_flash_simulator_pages_read(ULONG block, ULONG page, UCHAR* main_buffer, UCHAR* spare_buffer, ULONG pages); +UINT _lx_nand_flash_simulator_pages_write(ULONG block, ULONG page, UCHAR* main_buffer, UCHAR* spare_buffer, ULONG pages); +UINT _lx_nand_flash_simulator_pages_copy(ULONG source_block, ULONG source_page, ULONG destination_block, ULONG destination_page, ULONG pages, UCHAR* data_buffer); +UINT _lx_nand_flash_simulator_page_ecc_check(ULONG block, ULONG page); UINT _lx_nand_flash_simulator_initialize(LX_NAND_FLASH *nand_flash) { @@ -136,20 +145,70 @@ UINT _lx_nand_flash_simulator_initialize(LX_NAND_FLASH *nand_flash) nand_flash -> lx_nand_flash_driver_extra_bytes_set = _lx_nand_flash_simulator_extra_bytes_set; nand_flash -> lx_nand_flash_driver_system_error = _lx_nand_flash_simulator_system_error; - /* Setup local buffer for NAND flash operation. This buffer must be the page size of the NAND flash memory. */ - nand_flash -> lx_nand_flash_page_buffer = &nand_flash_simulator_buffer[0]; + nand_flash -> lx_nand_flash_driver_pages_read = _lx_nand_flash_simulator_pages_read; + nand_flash -> lx_nand_flash_driver_pages_write = _lx_nand_flash_simulator_pages_write; + nand_flash -> lx_nand_flash_driver_pages_copy = _lx_nand_flash_simulator_pages_copy; + + nand_flash -> lx_nand_flash_spare_data1_offset = SPARE_DATA1_OFFSET; + nand_flash -> lx_nand_flash_spare_data1_length = SPARE_DATA1_LENGTH; + + nand_flash -> lx_nand_flash_spare_data2_offset = SPARE_DATA2_OFFSET; + nand_flash -> lx_nand_flash_spare_data2_length = SPARE_DATA2_LENGTH; + + nand_flash -> lx_nand_flash_spare_total_length = SPARE_BYTES_PER_PAGE; /* Return success. */ return(LX_SUCCESS); } +UINT _lx_nand_flash_simulator_page_ecc_check(ULONG block, ULONG page) +{ +UINT i; +INT ecc_pos = 0; +UINT ecc_status = LX_SUCCESS; +UINT status; + + + for (i = 0; i < BYTES_PER_PHYSICAL_PAGE; i += 256) + { + status = lx_nand_flash_256byte_ecc_check((UCHAR*)&nand_memory_area[block].physical_pages[page].memory[i / sizeof(ULONG)], + &nand_memory_area[block].physical_pages[page].spare[ECC_BYTE_POSITION + ecc_pos]); + + if (status == LX_NAND_ERROR_NOT_CORRECTED) + { + ecc_status = LX_NAND_ERROR_NOT_CORRECTED; + break; + } + else if (status == LX_NAND_ERROR_CORRECTED) + { + ecc_status = LX_NAND_ERROR_CORRECTED; + } + + ecc_pos += 3; + } + + if (ecc_status == LX_NAND_ERROR_CORRECTED) + { + + return(LX_ERROR); + } + else if (ecc_status == LX_NAND_ERROR_NOT_CORRECTED) + { + + return(LX_ERROR); + } + return ecc_status; +} UINT _lx_nand_flash_simulator_read(ULONG block, ULONG page, ULONG *destination, ULONG words) { ULONG *flash_address; +UINT status; + status = _lx_nand_flash_simulator_page_ecc_check(block, page); + /* Pickup the flash address. */ flash_address = &(nand_memory_area[block].physical_pages[page].memory[0]); @@ -160,10 +219,40 @@ ULONG *flash_address; *destination++ = *flash_address++; } - return(LX_SUCCESS); + return(status); } +UINT _lx_nand_flash_simulator_pages_read(ULONG block, ULONG page, UCHAR* main_buffer, UCHAR* spare_buffer, ULONG pages) +{ + +UINT i; +UINT status; +UINT ecc_status = LX_SUCCESS; + + + for (i = 0; i < pages; i++) + { + if (main_buffer) + { + + status = _lx_nand_flash_simulator_read(block, page + i, (ULONG*)(main_buffer + i * BYTES_PER_PHYSICAL_PAGE), WORDS_PER_PHYSICAL_PAGE); + if (status == LX_NAND_ERROR_CORRECTED) + { + ecc_status = LX_NAND_ERROR_CORRECTED; + } + else if (status == LX_NAND_ERROR_NOT_CORRECTED) + { + ecc_status = LX_ERROR; + break; + } + } + + status = _lx_nand_flash_simulator_extra_bytes_get(block, page + i, spare_buffer + i * SPARE_BYTES_PER_PAGE, SPARE_BYTES_PER_PAGE); + } + return (ecc_status); +} + UINT _lx_nand_flash_simulator_write(ULONG block, ULONG page, ULONG *source, ULONG words) { @@ -180,7 +269,7 @@ ULONG *page_ptr = &(nand_memory_area[block].physical_pages[page].memory[0]); nand_block_diag[block].page_writes[page]++; if (nand_block_diag[block].page_writes[page] > nand_block_diag[block].max_page_writes[page]) nand_block_diag[block].max_page_writes[page] = nand_block_diag[block].page_writes[page]; - + /* Pickup the flash address. */ flash_address = &(nand_memory_area[block].physical_pages[page].memory[0]); @@ -210,7 +299,7 @@ ULONG *page_ptr = &(nand_memory_area[block].physical_pages[page].memory[0]); bytes_computed = bytes_computed + 256; /* Move the page buffer forward. */ - page_ptr = page_ptr + 256; + page_ptr = page_ptr + 64; ecc_bytes = ecc_bytes + 3; @@ -235,6 +324,51 @@ ULONG *page_ptr = &(nand_memory_area[block].physical_pages[page].memory[0]); return(LX_SUCCESS); } +UINT _lx_nand_flash_simulator_pages_write(ULONG block, ULONG page, UCHAR* main_buffer, UCHAR* spare_buffer, ULONG pages) +{ + +UINT i; +UINT status = LX_SUCCESS; + + + for (i = 0; i < pages; i++) + { + _lx_nand_flash_simulator_extra_bytes_set(block, page + i, spare_buffer + i * SPARE_BYTES_PER_PAGE, SPARE_BYTES_PER_PAGE); + status = _lx_nand_flash_simulator_write(block, page + i, (ULONG*)(main_buffer + i * BYTES_PER_PHYSICAL_PAGE), WORDS_PER_PHYSICAL_PAGE); + if (status == LX_INVALID_WRITE) + { + break; + } + + } + return (status); +} + + +UINT _lx_nand_flash_simulator_pages_copy(ULONG source_block, ULONG source_page, ULONG destination_block, ULONG destination_page, ULONG pages, UCHAR *data_buffer) +{ + UINT i; + UINT status = LX_SUCCESS; + + + for (i = 0; i < pages; i++) + { + status = _lx_nand_flash_simulator_pages_read(source_block, source_page + i, data_buffer, data_buffer + BYTES_PER_PHYSICAL_PAGE, 1); + if (status != LX_SUCCESS && status != LX_NAND_ERROR_CORRECTED) + { + break; + } + _lx_nand_flash_simulator_pages_write(destination_block, destination_page + i, data_buffer, data_buffer + BYTES_PER_PHYSICAL_PAGE, 1); + if (status != LX_SUCCESS) + { + break; + } + + } + return (status); + +} + UINT _lx_nand_flash_simulator_block_erase(ULONG block, ULONG erase_count) {