mirror of
https://github.com/eclipse-threadx/levelx.git
synced 2026-09-14 04:06:00 +08:00
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.
This commit is contained in:
+19
-11
@@ -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
|
||||
|
||||
+148
-70
@@ -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 <string.h>
|
||||
#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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
+28
-35
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
+17
-51
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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++;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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++;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
+20
-74
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
+82
-96
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
+244
-684
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
|
||||
Reference in New Issue
Block a user