10 Commits
Author SHA1 Message Date
Xiuwen Cai cef8e4ffeb Update on 23 Oct 2023. Expand to see details.
f203c27 Update headers and readme for 6.3.0 release.
40d3d10 Avoid clearing user extension in flash control block on opening flash
689dcc1 Added obsolete count and mapping bitmap cache for NOR flash. optimized block seraching logic.
b183526 Enable weekly pipeline build to avoid CodeQL expiration
2eec506 Enable codeql in onebranch pipeline
2023-10-23 05:31:43 +00:00
Xiuwen Cai e1a2752d6c Update on 12 May 2023. Expand to see details.
14f4439 Update CFS usage
9b8b2f0 Update CFS usage
0a78a87 Onboard to Central Feed Services
2bd4393 create LevelX cmsis-pack
2023-05-12 07:01:11 +00:00
Tiejun Zhou 39de3e54bd Update hardware license 2023-03-22 10:38:19 +08:00
Xiuwen Cai a8bc412907 Release 6.2.1 on 08 Mar 2023. Expand to see details.
075bb4c Update patch version.
a30e30b Update version and date for release.
a6b42b2 Update owners
6a3e60b Add user extension in flash control block
2023-03-08 08:32:05 +00:00
Liya Du 718fb514a9 Update LICENSED-HARDWARE.txt
Add new NXP and Renesas series.
2023-02-10 13:52:45 -08:00
Xiuwen Cai 27e3f5d915 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.
2023-01-18 08:37:32 +00:00
Liya Du dbf4f90598 Update issue templates 2022-11-15 21:05:54 -08:00
Tiejun Zhou 8b3a8293ce Release 6.2.0 2022-10-26 23:43:27 +00:00
Yuxin Zhou 2f639bac26 Release 6.1.12 2022-07-26 02:07:19 +00:00
Liya Du 9075ca321b Fix broken link for license 2022-06-13 12:28:22 -07:00
66 changed files with 5435 additions and 4965 deletions
+35
View File
@@ -0,0 +1,35 @@
---
name: Bug report
about: Create a report to help us improve Azure RTOS.
title: ''
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
Please also mention any information which could help others to understand
the problem you're facing:
- What target device are you using?
- Which version of Azure RTOS?
- What toolchain and environment?
- What have you tried to diagnose or workaround this issue?
**To Reproduce**
Steps to reproduce the behavior:
1. Build my project in IAR Workbench.
1. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Impact**
What impact does this issue have on your progress (e.g., annoyance, showstopper)
**Logs and console output**
If applicable, add console logs or other types of debug information like Wireshark capture as `.zip` file.
**Additional context**
Add any other context about the problem here.
+20
View File
@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea or enhancement to existing feature for Azure RTOS.
title: ''
labels: feature
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
@@ -0,0 +1,19 @@
---
name: Hardware or architecture support
about: Suggest adding hardware or new architecture support.
title: ''
labels: hardware
assignees: ''
---
**Is this request related to a particular hardware platform, SoC, board? Please describe.**
Describe in details the hardware support being requested and why this support benefits Azure RTOS.
**Describe why you are asking for this support?**
Describe why you are asking for this support.
If this is a new board or SoC, please state whether you are willing to maintain the Azure RTOS support together with you.
**Additional context**
Add any other context or graphics (drag-and-drop an image) about the hardware here.
+6
View File
@@ -6,6 +6,7 @@ project(levelx
)
option(LX_STANDALONE_ENABLE "Enable LevelX in standalone mode" OFF)
option(LX_ENABLE_FILE_SERVERS "Includes a dependency on FileX" ON)
if(NOT DEFINED THREADX_ARCH)
message(FATAL_ERROR "Error: THREADX_ARCH not defined")
@@ -25,6 +26,11 @@ if(NOT LX_STANDALONE_ENABLE)
"azrtos::threadx")
endif()
if(LX_ENABLE_FILE_SERVERS)
message(STATUS "LX_ENABLE_FILE_SERVERS - defined")
target_link_libraries(${PROJECT_NAME} PUBLIC "azrtos::filex")
endif()
# A place for generated/copied include files (no need to change)
set(CUSTOM_INC_DIR ${CMAKE_CURRENT_BINARY_DIR}/custom_inc)
+23 -20
View File
@@ -2,7 +2,6 @@ MICROSOFT SOFTWARE LICENSE TERMS
MICROSOFT AZURE RTOS
Shape
These license terms are an agreement between you and Microsoft Corporation (or
one of its affiliates). They apply to the software named above and any Microsoft
@@ -14,10 +13,11 @@ HAVE THE RIGHTS BELOW. BY USING THE SOFTWARE, YOU ACCEPT THESE TERMS.
1. INSTALLATION AND USE RIGHTS.
a) General. You may install and use the software and the included Microsoft
applications solely for internal development, testing and evaluation purposes.
Any distribution or production use requires a separate license as set forth in
Section 2.
a) General. You may (I) install, use and modify the software and (ii) install and use the included Microsoft
Applications (if any), each solely for internal development, testing and evaluation purposes.
Distribution or production use is governed by the license terms set forth in
Section 2. You may also obtain distribution or production use rights through a separate agreement with
Microsoft.
b) Contributions. Microsoft welcomes contributions to this software. In the event
that you make a contribution to this software you will be required to agree to a
@@ -25,7 +25,7 @@ Contributor License Agreement (CLA) declaring that you have the right to, and
actually do, grant Microsoft the rights to use your contribution. For details,
visit https://cla.microsoft.com.
c) Included Microsoft Applications. The software includes other Microsoft
c) Included Microsoft Applications. The software may include other Microsoft
applications which are governed by the licenses embedded in or made available
with those applications.
@@ -57,7 +57,6 @@ i. You may use the software in production (e.g. program the modified or unmodifi
software to devices you own or control) and distribute (i.e. make available to
third parties) the modified or unmodified binary image produced from this code.
ii. You may permit your device distributors or developers to copy and distribute the
binary image as programmed or to be programmed to your devices.
@@ -70,17 +69,12 @@ b) Requirements. For any code you distribute, you must:
i. when distributed in binary form, except as embedded in a device, include with
such distribution the terms of this agreement;
ii. when distributed in source code form to distributors or developers of your
devices, include with such distribution the terms of this agreement; and
iii. indemnify, defend and hold harmless Microsoft from any claims, including
attorneys fees, related to the distribution or use of your devices, except to
the extent that any claim is based solely on the unmodified software.
iii. indemnify, defend and hold harmless Microsoft from any claims, including claims arising from any High Risk Uses, and inclusive of attorneys fees, related to the distribution or use of your devices that include the software, except to the extent that any intellectual property claim is based solely on the unmodified software.
c) Restrictions. You may not:
i. use or modify the software to create a competing real time operating system
i. use or modify the software to create competing real time operating system
software;
ii. remove any copyright notices or licenses contained in the software;
@@ -179,12 +173,13 @@ breach of which would endanger the purpose of this agreement and the compliance
with which a party may constantly trust in (so-called "cardinal obligations").
In other cases of slight negligence, Microsoft will not be liable for slight
negligence.
12. DISCLAIMER OF WARRANTY. THE SOFTWARE IS LICENSED “AS IS.” YOU BEAR THE RISK OF
12. DISCLAIMER OF WARRANTY.
a) THE SOFTWARE IS LICENSED “AS IS.” YOU BEAR THE RISK OF
USING IT. MICROSOFT GIVES NO EXPRESS WARRANTIES, GUARANTEES, OR CONDITIONS. TO
THE EXTENT PERMITTED UNDER APPLICABLE LAWS, MICROSOFT EXCLUDES ALL IMPLIED
WARRANTIES, INCLUDING MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
NON-INFRINGEMENT.
b) HIGH RISK USE DISCLAIMER. WARNING: THE SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE WHERE FAILURE OR FAULT OF ANY KIND OF THE SOFTWARE COULD RESULT IN DEATH OR SERIOUS BODILY INJURY, OR IN PHYSICAL OR ENVIRONMENTAL DAMAGE (“collectively High Risk Use”). Accordingly, You must design and implement your hardware and software such that, in the event of any interruption, defect, error, or other failure of the software, the safety of people, property, and the environment are not reduced below a level that is reasonable, appropriate, and legal, whether in general or for a specific industry. Your High Risk Use of the software is at Your own risk.
13. LIMITATION ON AND EXCLUSION OF DAMAGES. IF YOU HAVE ANY BASIS FOR RECOVERING
DAMAGES DESPITE THE PRECEDING DISCLAIMER OF WARRANTY, YOU CAN RECOVER FROM
@@ -203,21 +198,29 @@ possibility of the damages. The above limitation or exclusion may not apply to
you because your state, province, or country may not allow the exclusion or
limitation of incidental, consequential, or other damages.
Please note: As this software is distributed in Canada, some of the clauses in
Please note: As this software is distributed in Canada, some of the clauses in
this agreement are provided below in French.
Remarque: Ce logiciel étant distribué au Canada, certaines des clauses dans ce
contrat sont fournies ci-dessous en français.
EXONÉRATION DE GARANTIE. Le logiciel visé par une licence est offert « tel quel
EXONÉRATION DE GARANTIE.
a) Le logiciel visé par une licence est offert « tel quel
». Toute utilisation de ce logiciel est à votre seule risque et péril. Microsoft
naccorde aucune autre garantie expresse. Vous pouvez bénéficier de droits
additionnels en vertu du droit local sur la protection des consommateurs, que ce
contrat ne peut modifier. La ou elles sont permises par le droit locale, les
garanties implicites de qualité marchande, dadéquation à un usage particulier
et dabsence de contrefaçon sont exclues.
b) CLAUSE DEXCLUSION DE RESPONSABILITÉ RELATIVE À LUTILISATION À HAUT RISQUE.
AVERTISSEMENT: LE LOGICIEL NEST PAS CONÇU OU DESTINÉ À ÊTRE UTILISÉ LORSQUUNE
DÉFAILLANCE OU UN DÉFAUT DE QUELQUE NATURE QUE CE SOIT POURRAIT ENTRAÎNER LA
MORT OU DES BLESSURES CORPORELLES GRAVES, OU DES DOMMAGES PHYSIQUES OU
ENVIRONNEMENTAUX (« Utilisation à haut risque »). Par conséquent, vous devez concevoir et mettre en
œuvre votre équipement et votre logiciel de manière à ce que, en cas dinterruption, de défaut, derreur
ou de toute autre défaillance du logiciel, la sécurité des personnes, des biens et de lenvironnement ne
soit pas réduite en dessous dun niveau raisonnable, approprié et légal, que ce soit en général ou pour
un secteur spécifique. Votre utilisation à haut risque du logiciel est à vos propres risques.
LIMITATION DES DOMMAGES-INTÉRÊTS ET EXCLUSION DE RESPONSABILITÉ POUR LES
DOMMAGES. Vous pouvez obtenir de Microsoft et de ses fournisseurs une
+2 -2
View File
@@ -1,6 +1,6 @@
LICENSED HARDWARE LIST
Last Updated: 2021-04-01
Last Updated: 2023-02-10
Microsoft has entered into OEM Agreements with manufacturers of the following
microprocessors and microcontrollers (the “hardware”) to enable those
@@ -31,7 +31,7 @@ NXP:
i.MX RT10xx and RT116x/7x series crossover MCUs
LPC5500 series
MCX N series
Renesas:
+113 -62
View File
@@ -1,94 +1,145 @@
# Azure RTOS LevelX
LevelX provides NAND and NOR flash wear leveling facilities to embedded applications. Since both NAND and NOR flash memory can only be erased a finite number of times, its critical to distribute the flash memory use evenly. This is typically called wear leveling and is the purpose behind LevelX. LevelX presents to the user an array of logical sectors that are mapped to physical flash memory inside of LevelX. Applications may use LevelX in conjunction with FileX or may read/write logical sectors directly. LevelX is designed for fault tolerance. Flash updates are performed in a multiple-step process that can be interrupted in each step. LevelX automatically recovers to the optimal state during the next operation.
LevelX provides NAND and NOR flash wear leveling facilities to embedded applications. Since both NAND and NOR flash memory can only be erased a finite number of times, its critical to distribute the flash memory use evenly. This is typically called **wear leveling** and is the purpose behind LevelX. LevelX presents to the user an array of logical sectors that are mapped to physical flash memory inside of LevelX. Applications may use LevelX in conjunction with FileX or may read/write logical sectors directly. LevelX is designed for fault tolerance. Flash updates are performed in a multiple-step process that can be interrupted in each step. LevelX automatically recovers to the optimal state during the next operation.
## Documentation
## Getting Started
Documentation for this library can be found here: https://github.com/azure-rtos/levelx/releases/download/v6.0_rel/Azure_RTOS_LevelX_User_Guide.pdf
Azure RTOS LevelX as part of Azure RTOS has been integrated to the semiconductor's SDKs and development environment. You can develop using the tools of choice from [STMicroelectronics](https://www.st.com/content/st_com/en/campaigns/x-cube-azrtos-azure-rtos-stm32.html), [NXP](https://www.nxp.com/design/software/embedded-software/azure-rtos-for-nxp-microcontrollers:AZURE-RTOS), [Renesas](https://github.com/renesas/azure-rtos) and [Microchip](https://mu.microchip.com/get-started-simplifying-your-iot-design-with-azure-rtos).
# Understanding inter-component dependencies
See [Overview of Azure RTOS LevelX](https://learn.microsoft.com/azure/rtos/levelx/overview-levelx) for the high-level overview, and all documentation and APIs can be found in: [Azure RTOS LevelX documentation](https://learn.microsoft.com/azure/rtos/levelx/).
The main components of Azure RTOS are each provided in their own repository, but there are dependencies between them--shown in the following graph--that are important to understand when setting up your builds.
## Repository Structure and Usage
### Directory layout
.
├── cmake # CMakeList files for building the project
├── common # Core LevelX files
├── samples # Sample codes
├── LICENSE.txt # License terms
├── LICENSE-HARDWARE.txt # Licensed hardware from semiconductors
├── CONTRIBUTING.md # Contribution guidance
└── SECURITY.md # Microsoft repo security guidance
### Branches & Releases
The master branch has the most recent code with all new features and bug fixes. It does not represent the latest General Availability (GA) release of the library. Each official release (preview or GA) will be tagged to mark the commit and push it into the Github releases tab, e.g. `v6.2-rel`.
> When you see xx-xx-xxxx, 6.x or x.x in function header, this means the file is not officially released yet. They will be updated in the next release. See example below.
```
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_initialize_low_level Cortex-M23/GNU */
/* 6.x */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function is responsible for any low-level processor */
/* initialization, including setting up interrupt vectors, setting */
/* up a periodic timer interrupt source, saving the system stack */
/* pointer for use in ISR processing later, and finding the first */
/* available RAM memory address for tx_application_define. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _tx_initialize_kernel_enter ThreadX entry function */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 09-30-2020 Scott Larson Initial Version 6.1 */
/* xx-xx-xxxx Scott Larson Include tx_user.h, */
/* resulting in version 6.x */
/* */
/**************************************************************************/
```
## Component dependencies
The main components of Azure RTOS are each provided in their own repository, but there are dependencies between them, as shown in the following graph. This is important to understand when setting up your builds.
![dependency graph](docs/deps.png)
# Building and using the library
> You will have to take the dependency graph above into account when building anything other than ThreadX itself.
## Prerequisites
### Building and using the library
Install the following tools:
Instruction for building the LevelX as static library using Arm GNU Toolchain and CMake. If you are using toolchain and IDE from semiconductor, you might follow its own instructions to use Azure RTOS components as explained in the [Getting Started](#getting-started) section.
* [CMake](https://cmake.org/download/) version 3.0 or later
* [GCC compilers for arm-none-eabi](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads)
* [Ninja](https://ninja-build.org/)
1. Install the following tools:
## Cloning the repo
* [CMake](https://cmake.org/download/) version 3.0 or later
* [Arm GNU Toolchain for arm-none-eabi](https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads)
* [Ninja](https://ninja-build.org/)
```bash
$ git clone https://github.com/azure-rtos/levelx.git
```
1. Build the [ThreadX library](https://github.com/azure-rtos/threadx#building-and-using-the-library) as the dependency.
## Building as a static library
1. Cloning the repo.
Each component of Azure RTOS comes with a composible CMake-based build system that supports many different MCUs and host systems. Integrating any of these components into your device app code is as simple as adding a git submodule and then including it in your build using the CMake command `add_subdirectory()`.
```bash
$ git clone --recursive https://github.com/azure-rtos/levelx.git
```
While the typical usage pattern is to include threadx into your device code source tree to be built & linked with your code, you can compile this project as a standalone static library to confirm your build is set up correctly.
1. Define the features and addons you need in `lx_user.h` and build together with the component source code. You can refer to [`lx_user_sample.h`](https://github.com/azure-rtos/levelx/blob/master/common/inc/lx_user_sample.h) as an example.
```bash
$ cmake -Bbuild -DCMAKE_TOOLCHAIN_FILE=cmake/cortex_m4.cmake -GNinja .
1. Building as a static library
$ cmake --build ./build
```
Each component of Azure RTOS comes with a composable CMake-based build system that supports many different MCUs and host systems. Integrating any of these components into your device app code is as simple as adding a git submodule and then including it in your build using the CMake `add_subdirectory()`.
NOTE: You will have to take the dependency graph above into account when building anything other than threadx itself.
While the typical usage pattern is to include LevelX into your device code source tree to be built & linked with your code, you can compile this project as a standalone static library to confirm your build is set up correctly.
# Repository Structure and Usage
An example of building the library for Cortex-M4:
## Branches & Releases
```bash
$ cmake -Bbuild -GNinja -DCMAKE_TOOLCHAIN_FILE=cmake/cortex_m4.cmake .
The master branch has the most recent code with all new features and bug fixes. It does not represent the latest General Availability (GA) release of the library.
$ cmake --build ./build
```
## Releases
## Professional support
Each official release (preview or GA) will be tagged to mark the commit and push it into the Github releases tab, e.g. `v6.0-rel`.
[Professional support plans](https://azure.microsoft.com/support/options/) are available from Microsoft. For community support and others, see the [Resources](#resources) section below.
## Directory layout
## Licensing
```
- cmake
- common
- inc
- src
- samples
```
License terms for using Azure RTOS are defined in the LICENSE.txt file of this repo. Please refer to this file for all definitive licensing information. No additional license fees are required for deploying Azure RTOS on hardware defined in the [LICENSED-HARDWARE.txt](./LICENSED-HARDWARE.txt) file. If you are using hardware not listed in the file or having licensing questions in general, please contact Microsoft directly at https://aka.ms/azrtos-license.
# Security
## Resources
The following are references to additional Azure RTOS resources:
- **Product introduction and white papers**: https://azure.com/rtos
- **General technical questions**: https://aka.ms/QnA/azure-rtos
- **Product issues and bugs, or feature requests**: https://github.com/azure-rtos/levelx/issues
- **Licensing and sales questions**: https://aka.ms/azrtos-license
- **Product roadmap and support policy**: https://aka.ms/azrtos/lts
- **Blogs and videos**: http://msiotblog.com and https://aka.ms/iotshow
- **Azure RTOS TraceX Installer**: https://aka.ms/azrtos-tracex-installer
You can also check [previous questions](https://stackoverflow.com/questions/tagged/azure-rtos+levelx) or ask new ones on StackOverflow using the `azure-rtos` and `levelx` tags.
## Security
Azure RTOS provides OEMs with components to secure communication and to create code and data isolation using underlying MCU/MPU hardware protection mechanisms. It is ultimately the responsibility of the device builder to ensure the device fully meets the evolving security requirements associated with its specific use case.
# Licensing
## Contribution
License terms for using Azure RTOS are defined in the LICENSE.txt file of this repo. Please refer to this file for all definitive licensing information. No additional license fees are required for deploying Azure RTOS on hardware defined in the LICENSED-HARDWARE.txt file. If you are using hardware not defined in the LICENSED-HARDWARE.txt file or have licensing questions in general, please contact Microsoft directly at https://aka.ms/azrtos-license.
# Contribution, feedback, issues, and professional support
If you encounter any bugs, have suggestions for new features, or if you would like to become an active contributor to this project, please follow the instructions provided in the contribution guideline for the corresponding repo.
For basic support, click Issues in the command bar or post a question to [Stack Overflow](http://stackoverflow.com/questions/tagged/azure-rtos+threadx) using the `threadx` and `azure-rtos` tags.
Professional support plans (https://azure.microsoft.com/en-us/support/options/) are available from Microsoft.
# Additional Resources
The following are references to additional Azure RTOS and Azure IoT in general:
| Content | Link |
|---|---|
| TraceX Installer | https://aka.ms/azrtos-tracex-installer |
| Azure RTOS Documentation and Guides: | https://docs.microsoft.com/azure/rtos |
| Azure RTOS Website: | https://azure.microsoft.com/services/rtos/ |
| Azure RTOS Sales Questions: | https://azure-rtos.ms-iot-contact.com/ |
| Azure RTOS Product Support Policy | https://aka.ms/azrtos/lts |
| Azure RTOS Functional Safety Artifacts | https://aka.ms/azrtos/tuv |
| For technical questions check out Microsoft Q/A for Azure IoT | https://aka.ms/QnA/azure-rtos |
| Internet of Things Show for latest announcements and online training | https://aka.ms/iotshow |
| IoT Tech Community | https://aka.ms/community/azure-rtos |
Please follow the instructions provided in the [CONTRIBUTING.md](./CONTRIBUTING.md) for the corresponding repository.
+19 -11
View File
@@ -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
+224 -68
View File
@@ -26,7 +26,7 @@
/* APPLICATION INTERFACE DEFINITION RELEASE */
/* */
/* lx_api.h PORTABLE C */
/* 6.1.11 */
/* 6.3.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
@@ -69,6 +69,23 @@
/* 04-25-2022 William E. Lamie Modified comment(s), and */
/* updated product constants, */
/* resulting in version 6.1.11 */
/* 07-29-2022 William E. Lamie Modified comment(s), and */
/* updated product constants, */
/* resulting in version 6.1.12 */
/* 10-31-2022 Xiuwen Cai Modified comment(s), and */
/* updated product constants, */
/* resulting in version 6.2.0 */
/* 03-08-2023 Xiuwen Cai Modified comment(s), */
/* modified NAND logic, */
/* added new driver interface */
/* and user extension, */
/* resulting in version 6.2.1 */
/* 10-31-2023 Xiuwen Cai Modified comment(s), */
/* made LX_NOR_SECTOR_SIZE */
/* configurable, added mapping */
/* bitmap and obsolete count */
/* cache for NOR flash, */
/* resulting in version 6.3.0 */
/* */
/**************************************************************************/
@@ -143,6 +160,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
@@ -155,6 +176,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
@@ -172,8 +197,8 @@ typedef unsigned long long ULONG64;
/* Define basic constants for the LevelX Stack. */
#define AZURE_RTOS_LEVELX
#define LEVELX_MAJOR_VERSION 6
#define LEVELX_MINOR_VERSION 1
#define LEVELX_PATCH_VERSION 11
#define LEVELX_MINOR_VERSION 3
#define LEVELX_PATCH_VERSION 0
/* Define general LevelX Constants. */
@@ -200,6 +225,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
@@ -211,7 +239,9 @@ typedef unsigned long long ULONG64;
#define LX_NOR_FLASH_OPENED ((ULONG) 0x4E4F524F)
#define LX_NOR_FLASH_CLOSED ((ULONG) 0x4E4F5244)
#ifndef LX_NOR_SECTOR_SIZE
#define LX_NOR_SECTOR_SIZE (512/sizeof(ULONG))
#endif
#define LX_NOR_FLASH_MIN_LOGICAL_SECTOR_OFFSET 1
#define LX_NOR_FLASH_MAX_LOGICAL_SECTOR_OFFSET 2
#ifndef LX_NOR_FLASH_MAX_ERASE_COUNT_DELTA
@@ -224,6 +254,11 @@ typedef unsigned long long ULONG64;
#ifndef LX_NOR_EXTENDED_CACHE_SIZE
#define LX_NOR_EXTENDED_CACHE_SIZE 8 /* Maximum number of extended cache sectors. */
#endif
#ifdef LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE
#ifndef LX_NOR_OBSOLETE_COUNT_CACHE_TYPE
#define LX_NOR_OBSOLETE_COUNT_CACHE_TYPE UCHAR
#endif
#endif
/* Define the mask for the hash index into the sector mapping cache table. The sector mapping cache is divided
@@ -269,6 +304,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:
@@ -291,26 +345,68 @@ 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;
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 logical sector cache entry structure. */
/* Determine if the flash control block has an extension defined. If not,
define the extension to whitespace. */
typedef struct LX_NAND_SECTOR_MAPPING_CACHE_ENTRY_STRUCT
{
#ifndef LX_NAND_FLASH_DIRECT_MAPPING_CACHE
ULONG lx_nand_sector_mapping_cache_logical_sector;
#ifndef LX_NAND_FLASH_USER_EXTENSION
#define LX_NAND_FLASH_USER_EXTENSION
#endif
USHORT lx_nand_sector_mapping_cache_block;
USHORT lx_nand_sector_mapping_cache_page;
} LX_NAND_SECTOR_MAPPING_CACHE_ENTRY;
/* Define the NAND flash control block structure. */
@@ -325,20 +421,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;
@@ -347,15 +465,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;
@@ -368,16 +477,22 @@ typedef struct LX_NAND_FLASH_STRUCT
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;
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
UINT (*lx_nand_flash_driver_read)(struct LX_NAND_FLASH_STRUCT *nand_flash, ULONG block, ULONG page, ULONG *destination, ULONG words);
UINT (*lx_nand_flash_driver_write)(struct LX_NAND_FLASH_STRUCT *nand_flash, ULONG block, ULONG page, ULONG *source, ULONG words);
UINT (*lx_nand_flash_driver_block_erase)(struct LX_NAND_FLASH_STRUCT *nand_flash, ULONG block, ULONG erase_count);
UINT (*lx_nand_flash_driver_block_erased_verify)(struct LX_NAND_FLASH_STRUCT *nand_flash, ULONG block);
UINT (*lx_nand_flash_driver_page_erased_verify)(struct LX_NAND_FLASH_STRUCT *nand_flash, ULONG block, ULONG page);
UINT (*lx_nand_flash_driver_block_status_get)(struct LX_NAND_FLASH_STRUCT *nand_flash, ULONG block, UCHAR *bad_block_flag);
UINT (*lx_nand_flash_driver_block_status_set)(struct LX_NAND_FLASH_STRUCT *nand_flash, ULONG block, UCHAR bad_block_flag);
UINT (*lx_nand_flash_driver_extra_bytes_get)(struct LX_NAND_FLASH_STRUCT *nand_flash, ULONG block, ULONG page, UCHAR *destination, UINT size);
UINT (*lx_nand_flash_driver_extra_bytes_set)(struct LX_NAND_FLASH_STRUCT *nand_flash, ULONG block, ULONG page, UCHAR *source, UINT size);
UINT (*lx_nand_flash_driver_system_error)(struct LX_NAND_FLASH_STRUCT *nand_flash, UINT error_code, ULONG block, ULONG page);
UINT (*lx_nand_flash_driver_pages_read)(struct LX_NAND_FLASH_STRUCT *nand_flash, ULONG block, ULONG page, UCHAR* main_buffer, UCHAR* spare_buffer, ULONG pages);
UINT (*lx_nand_flash_driver_pages_write)(struct LX_NAND_FLASH_STRUCT *nand_flash, ULONG block, ULONG page, UCHAR* main_buffer, UCHAR* spare_buffer, ULONG pages);
UINT (*lx_nand_flash_driver_pages_copy)(struct LX_NAND_FLASH_STRUCT *nand_flash, ULONG source_block, ULONG source_page, ULONG destination_block, ULONG destination_page, ULONG pages, UCHAR* data_buffer);
#else
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);
UINT (*lx_nand_flash_driver_block_erase)(ULONG block, ULONG erase_count);
@@ -389,18 +504,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];
/* 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;
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);
#endif
UCHAR *lx_nand_flash_page_buffer;
UINT lx_nand_flash_page_buffer_size;
#ifdef LX_THREAD_SAFE_ENABLE
@@ -414,6 +523,10 @@ typedef struct LX_NAND_FLASH_STRUCT
struct LX_NAND_FLASH_STRUCT *lx_nand_flash_open_next,
*lx_nand_flash_open_previous;
/* Define the user extension in the flash control block. This
is typically defined in lx_user.h. */
LX_NAND_FLASH_USER_EXTENSION
} LX_NAND_FLASH;
@@ -438,6 +551,13 @@ typedef struct LX_NOR_FLASH_EXTENDED_CACHE_ENTRY_STRUCT
} LX_NOR_FLASH_EXTENDED_CACHE_ENTRY;
/* Determine if the flash control block has an extension defined. If not,
define the extension to whitespace. */
#ifndef LX_NOR_FLASH_USER_EXTENSION
#define LX_NOR_FLASH_USER_EXTENSION
#endif
/* Define the NOR flash control block structure. */
typedef struct LX_NOR_FLASH_STRUCT
@@ -459,6 +579,7 @@ typedef struct LX_NOR_FLASH_STRUCT
ULONG lx_nor_flash_mapped_physical_sectors;
ULONG lx_nor_flash_obsolete_physical_sectors;
ULONG lx_nor_flash_minimum_erase_count;
ULONG lx_nor_flash_minimum_erased_blocks;
ULONG lx_nor_flash_maximum_erase_count;
ULONG lx_nor_flash_free_block_search;
@@ -483,11 +604,19 @@ typedef struct LX_NOR_FLASH_STRUCT
ULONG lx_nor_flash_diagnostic_sector_not_free;
ULONG lx_nor_flash_diagnostic_sector_data_not_free;
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
UINT (*lx_nor_flash_driver_read)(struct LX_NOR_FLASH_STRUCT *nor_flash, ULONG *flash_address, ULONG *destination, ULONG words);
UINT (*lx_nor_flash_driver_write)(struct LX_NOR_FLASH_STRUCT *nor_flash, ULONG *flash_address, ULONG *source, ULONG words);
UINT (*lx_nor_flash_driver_block_erase)(struct LX_NOR_FLASH_STRUCT *nor_flash, ULONG block, ULONG erase_count);
UINT (*lx_nor_flash_driver_block_erased_verify)(struct LX_NOR_FLASH_STRUCT *nor_flash, ULONG block);
UINT (*lx_nor_flash_driver_system_error)(struct LX_NOR_FLASH_STRUCT *nor_flash, UINT error_code);
#else
UINT (*lx_nor_flash_driver_read)(ULONG *flash_address, ULONG *destination, ULONG words);
UINT (*lx_nor_flash_driver_write)(ULONG *flash_address, ULONG *source, ULONG words);
UINT (*lx_nor_flash_driver_block_erase)(ULONG block, ULONG erase_count);
UINT (*lx_nor_flash_driver_block_erased_verify)(ULONG block);
UINT (*lx_nor_flash_driver_system_error)(UINT error_code);
#endif
ULONG *lx_nor_flash_sector_buffer;
UINT lx_nor_flash_sector_mapping_cache_enabled;
@@ -501,6 +630,15 @@ typedef struct LX_NOR_FLASH_STRUCT
lx_nor_flash_extended_cache[LX_NOR_EXTENDED_CACHE_SIZE];
ULONG lx_nor_flash_extended_cache_hits;
ULONG lx_nor_flash_extended_cache_misses;
#ifdef LX_NOR_ENABLE_MAPPING_BITMAP
ULONG *lx_nor_flash_extended_cache_mapping_bitmap;
ULONG lx_nor_flash_extended_cache_mapping_bitmap_max_logical_sector;
#endif
#ifdef LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE
LX_NOR_OBSOLETE_COUNT_CACHE_TYPE
*lx_nor_flash_extended_cache_obsolete_count;
ULONG lx_nor_flash_extended_cache_obsolete_count_max_block;
#endif
#endif
#ifdef LX_THREAD_SAFE_ENABLE
@@ -515,6 +653,10 @@ typedef struct LX_NOR_FLASH_STRUCT
struct LX_NOR_FLASH_STRUCT *lx_nor_flash_open_next,
*lx_nor_flash_open_previous;
/* Define the user extension in the flash control block. This
is typically defined in lx_user.h. */
LX_NOR_FLASH_USER_EXTENSION
} LX_NOR_FLASH;
@@ -564,6 +706,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
@@ -571,6 +714,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
@@ -592,13 +738,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);
@@ -613,25 +765,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);
+44 -14
View File
@@ -26,7 +26,7 @@
/* PORT SPECIFIC C INFORMATION RELEASE */
/* */
/* lx_user.h PORTABLE C */
/* 6.1.7 */
/* 6.3.0 */
/* */
/* AUTHOR */
/* */
@@ -48,6 +48,14 @@
/* 06-02-2021 Bhupendra Naphade Modified comment(s), and */
/* added standalone support, */
/* resulting in version 6.1.7 */
/* 03-08-2023 Xiuwen Cai Modified comment(s), and */
/* added new NAND options, */
/* resulting in version 6.2.1 */
/* 10-31-2023 Xiuwen Cai Modified comment(s), */
/* added options for mapping , */
/* bitmap cache and obsolete */
/* count cache, */
/* resulting in version 6.3.0 */
/* */
/**************************************************************************/
@@ -71,23 +79,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
@@ -120,7 +118,39 @@
/* #define LX_STANDALONE_ENABLE */
/* Define user extension for NOR flash control block. User extension is placed at the end of flash control block and it is not cleared on opening flash. */
/*
#define LX_NOR_FLASH_USER_EXTENSION ????
*/
/* Define user extension for NAND flash control block. User extension is placed at the end of flash control block and it is not cleared on opening flash. */
/*
#define LX_NAND_FLASH_USER_EXTENSION ????
*/
/* Determine if logical sector mapping bitmap should be enabled in extended cache.
Cache memory will be allocated to sector mapping bitmap first. One bit can be allocated for each physical sector. */
/*
#define LX_NOR_ENABLE_MAPPING_BITMAP
*/
/* Determine if obsolete count cache should be enabled in extended cache.
Cache memory will be allocated to obsolete count cache after the mapping bitmap if enabled,
and the rest of the cache memory is allocated to sector cache. */
/*
#define LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE
*/
/* Defines obsolete count cache element size. If number of sectors per block is greater than 256, use USHORT instead of UCHAR. */
/*
#define LX_NOR_OBSOLETE_COUNT_CACHE_TYPE UCHAR
*/
/* Define the logical sector size for NOR flash. The sector size is in units of 32-bit words.
This sector size should match the sector size used in file system. */
/*
#define LX_NOR_SECTOR_SIZE (512/sizeof(ULONG))
*/
#endif
+8 -2
View File
@@ -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.2.1 */
/* 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 */
/* 03-08-2023 Xiuwen Cai Modified comment(s), */
/* changed to use new API, */
/* resulting in version 6.2.1 */
/* */
/**************************************************************************/
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)
+24 -15
View File
@@ -36,19 +36,19 @@ LX_NOR_FLASH nor_flash;
the fx_media_open call.
fx_media_format(&ram_disk,
_fx_nor_sim_driver, // Driver entry
FX_NULL, // Unused
media_memory, // Media buffer pointer
sizeof(media_memory), // Media buffer size
"MY_NOR_DISK", // Volume Name
1, // Number of FATs
32, // Directory Entries
0, // Hidden sectors
120, // Total sectors
512, // Sector size
1, // Sectors per cluster
1, // Heads
1); // Sectors per track
_fx_nor_sim_driver, // Driver entry
FX_NULL, // Unused
media_memory, // Media buffer pointer
sizeof(media_memory), // Media buffer size
"MY_NOR_DISK", // Volume Name
1, // Number of FATs
32, // Directory Entries
0, // Hidden sectors
120, // Total sectors
LX_NOR_SECTOR_SIZE * sizeof(ULONG), // Sector size
1, // Sectors per cluster
1, // Heads
1); // Sectors per track
*/
@@ -231,7 +231,7 @@ UINT status;
/* Move to the next entries. */
logical_sector++;
destination_buffer = destination_buffer + 512;
destination_buffer = destination_buffer + media_ptr -> fx_media_bytes_per_sector;
}
/* Successful driver request. */
@@ -265,7 +265,7 @@ UINT status;
/* Move to the next entries. */
logical_sector++;
source_buffer = source_buffer + 512;
source_buffer = source_buffer + media_ptr -> fx_media_bytes_per_sector;
}
/* Successful driver request. */
@@ -428,6 +428,15 @@ UINT status;
case FX_DRIVER_BOOT_WRITE:
{
/* Make sure the media bytes per sector equals to the LevelX logical sector size. */
if (media_ptr -> fx_media_bytes_per_sector != (LX_NOR_SECTOR_SIZE) * sizeof(ULONG))
{
/* Sector size mismatch, return error. */
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
break;
}
/* Write the boot record and return to the caller. */
/* Setup the source buffer. */
@@ -40,7 +40,7 @@
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_256byte_ecc_compute PORTABLE C */
/* 6.1.7 */
/* 6.2.1 */
/* 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 */
/* 03-08-2023 Xiuwen Cai Modified comment(s), */
/* inverted output, */
/* resulting in version 6.2.1 */
/* */
/**************************************************************************/
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);
}
+97
View File
@@ -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.2.1 */
/* 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 */
/* */
/* 03-08-2023 Xiuwen Cai Initial Version 6.2.1 */
/* */
/**************************************************************************/
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);
}
+231
View File
@@ -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.2.1 */
/* 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 */
/* */
/* 03-08-2023 Xiuwen Cai Initial Version 6.2.1 */
/* */
/**************************************************************************/
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);
}
+118
View File
@@ -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.2.1 */
/* 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 */
/* */
/* 03-08-2023 Xiuwen Cai Initial Version 6.2.1 */
/* */
/**************************************************************************/
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);
}
@@ -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.2.1 */
/* 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 */
/* 03-08-2023 Xiuwen Cai Initial Version 6.2.1 */
/* */
/**************************************************************************/
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);
}
}
}
}
}
-620
View File
@@ -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);
}
@@ -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.2.1 */
/* 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 */
/* 03-08-2023 Xiuwen Cai Initial Version 6.2.1 */
/* */
/**************************************************************************/
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)
{
/* Save the block status to status table. */
nand_flash -> lx_nand_flash_block_status_table[block] = (USHORT)block_status;
/* Determine if the page 0 cache is enabled. */
if (nand_flash -> lx_nand_flash_page_0_cache != LX_NULL)
{
/* 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);
/* Yes, the page 0 cache is enabled. */
/* Calculate the cache index. */
cache_index = (block * (nand_flash -> lx_nand_flash_pages_per_block + 1));
/* 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);
+252
View File
@@ -0,0 +1,252 @@
/**************************************************************************/
/* */
/* 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.2.1 */
/* 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 */
/* */
/* 03-08-2023 Xiuwen Cai Initial Version 6.2.1 */
/* */
/**************************************************************************/
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. */
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
status = (nand_flash -> lx_nand_flash_driver_pages_read)(nand_flash, source_block, (ULONG)source_page, LX_NULL, spare_buffer_ptr, 1);
#else
status = (nand_flash -> lx_nand_flash_driver_pages_read)(source_block, (ULONG)source_page, LX_NULL, spare_buffer_ptr, 1);
#endif
/* 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. */
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
status = (nand_flash -> lx_nand_flash_driver_pages_copy)(nand_flash, source_block, (ULONG)source_page, destination_block, destination_page, 1, nand_flash -> lx_nand_flash_page_buffer);
#else
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);
#endif
/* 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. */
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
status = (nand_flash -> lx_nand_flash_driver_pages_copy)(nand_flash, source_block, (ULONG)source_page, destination_block, destination_page, number_of_pages, nand_flash -> lx_nand_flash_page_buffer);
#else
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);
#endif
/* 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);
}
+7 -29
View File
@@ -40,7 +40,7 @@
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_defragment PORTABLE C */
/* 6.1.7 */
/* 6.2.1 */
/* 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 */
/* 03-08-2023 Xiuwen Cai Modified comment(s), */
/* deprecated this API, */
/* resulting in version 6.2.1 */
/* */
/**************************************************************************/
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);
}
+9 -45
View File
@@ -40,7 +40,7 @@
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_driver_block_erase PORTABLE C */
/* 6.1.7 */
/* 6.2.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
@@ -76,63 +76,27 @@
/* resulting in version 6.1 */
/* 06-02-2021 Bhupendra Naphade Modified comment(s), */
/* resulting in version 6.1.7 */
/* 03-08-2023 Xiuwen Cai Modified comment(s), */
/* removed cache support, */
/* added new driver interface, */
/* resulting in version 6.2.1 */
/* */
/**************************************************************************/
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++;
/* Call driver erase block function. */
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
status = (nand_flash -> lx_nand_flash_driver_block_erase)(nand_flash, block, erase_count);
#else
status = (nand_flash -> lx_nand_flash_driver_block_erase)(block, erase_count);
#endif
/* Return status. */
return(status);
@@ -40,7 +40,7 @@
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_driver_block_erased_verify PORTABLE C */
/* 6.1.7 */
/* 6.2.1 */
/* 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 */
/* 03-08-2023 Xiuwen Cai Modified comment(s), */
/* added new driver interface, */
/* resulting in version 6.2.1 */
/* */
/**************************************************************************/
UINT _lx_nand_flash_driver_block_erased_verify(LX_NAND_FLASH *nand_flash, ULONG block)
@@ -88,8 +91,11 @@ UINT status;
nand_flash -> lx_nand_flash_diagnostic_block_erased_verifies++;
/* Call driver block erased verify function. */
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
status = (nand_flash -> lx_nand_flash_driver_block_erased_verify)(nand_flash, block);
#else
status = (nand_flash -> lx_nand_flash_driver_block_erased_verify)(block);
#endif
/* Return status. */
return(status);
}
@@ -40,7 +40,7 @@
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_driver_block_status_get PORTABLE C */
/* 6.1.7 */
/* 6.2.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
@@ -78,6 +78,10 @@
/* resulting in version 6.1 */
/* 06-02-2021 Bhupendra Naphade Modified comment(s), */
/* resulting in version 6.1.7 */
/* 03-08-2023 Xiuwen Cai Modified comment(s), */
/* removed cache support, */
/* added new driver interface, */
/* resulting in version 6.2.1 */
/* */
/**************************************************************************/
UINT _lx_nand_flash_driver_block_status_get(LX_NAND_FLASH *nand_flash, ULONG block, UCHAR *bad_block_flag)
@@ -86,48 +90,15 @@ 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. */
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
status = (nand_flash -> lx_nand_flash_driver_block_status_get)(nand_flash, block, bad_block_flag);
#else
status = (nand_flash -> lx_nand_flash_driver_block_status_get)(block, bad_block_flag);
#endif
/* Return status. */
return(status);
@@ -40,7 +40,7 @@
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_driver_block_status_set PORTABLE C */
/* 6.1.7 */
/* 6.2.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
@@ -78,6 +78,10 @@
/* resulting in version 6.1 */
/* 06-02-2021 Bhupendra Naphade Modified comment(s), */
/* resulting in version 6.1.7 */
/* 03-08-2023 Xiuwen Cai Modified comment(s), */
/* removed cache support, */
/* added new driver interface, */
/* resulting in version 6.2.1 */
/* */
/**************************************************************************/
UINT _lx_nand_flash_driver_block_status_set(LX_NAND_FLASH *nand_flash, ULONG block, UCHAR bad_block_flag)
@@ -86,19 +90,15 @@ 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++;
/* Call driver block status set function. */
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
status = (nand_flash -> lx_nand_flash_driver_block_status_set)(nand_flash, block, bad_block_flag);
#else
status = (nand_flash -> lx_nand_flash_driver_block_status_set)(block, bad_block_flag);
#endif
/* Return status. */
return(status);
@@ -40,7 +40,7 @@
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_driver_page_erased_verify PORTABLE C */
/* 6.1.7 */
/* 6.2.1 */
/* 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 */
/* 03-08-2023 Xiuwen Cai Modified comment(s), */
/* added new driver interface, */
/* resulting in version 6.2.1 */
/* */
/**************************************************************************/
UINT _lx_nand_flash_driver_page_erased_verify(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page)
@@ -88,8 +91,11 @@ UINT status;
nand_flash -> lx_nand_flash_diagnostic_page_erased_verifies++;
/* Call driver page erased verify function. */
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
status = (nand_flash -> lx_nand_flash_driver_page_erased_verify)(nand_flash, block, page);
#else
status = (nand_flash -> lx_nand_flash_driver_page_erased_verify)(block, page);
#endif
/* Return status. */
return(status);
}
-184
View File
@@ -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);
}
@@ -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.2.1 */
/* 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 */
/* 03-08-2023 Xiuwen Cai Initial Version 6.2.1 */
/* */
/**************************************************************************/
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
{
/* 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);
/* Calculate the cache index. */
cache_index = (block * nand_flash -> lx_nand_flash_pages_per_block) + page;
/* 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.2.1 */
/* 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 */
/* 03-08-2023 Xiuwen Cai Modified comment(s), */
/* deprecated this API, */
/* resulting in version 6.2.1 */
/* */
/**************************************************************************/
UINT _lx_nand_flash_extended_cache_enable(LX_NAND_FLASH *nand_flash, VOID *memory, ULONG size)
{
UCHAR *working_ptr;
ULONG adjust_size;
ULONG i;
LX_PARAMETER_NOT_USED(nand_flash);
LX_PARAMETER_NOT_USED(memory);
LX_PARAMETER_NOT_USED(size);
/* Setup the working pointer. */
working_ptr = (UCHAR *) memory;
/* 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);
}
+288
View File
@@ -0,0 +1,288 @@
/**************************************************************************/
/* */
/* 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.3.0 */
/* 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 */
/* */
/* 03-08-2023 Xiuwen Cai Initial Version 6.2.1 */
/* 10-31-2023 Xiuwen Cai Modified comment(s), */
/* avoided clearing user */
/* extension in flash control */
/* block, */
/* resulting in version 6.3.0 */
/* */
/**************************************************************************/
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. User extension is not cleared. */
LX_MEMSET(nand_flash, 0, (ULONG)((UCHAR*)&(nand_flash -> lx_nand_flash_open_previous) - (UCHAR*)nand_flash) + sizeof(nand_flash -> lx_nand_flash_open_previous));
/* 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.2.1 */
/* 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 */
/* */
/* 03-08-2023 Xiuwen Cai Initial Version 6.2.1 */
/* */
/**************************************************************************/
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.2.1 */
/* 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 */
/* */
/* 03-08-2023 Xiuwen Cai Initial Version 6.2.1 */
/* */
/**************************************************************************/
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.2.1 */
/* 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 */
/* */
/* 03-08-2023 Xiuwen Cai Initial Version 6.2.1 */
/* */
/**************************************************************************/
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.2.1 */
/* 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 */
/* */
/* 03-08-2023 Xiuwen Cai Initial Version 6.2.1 */
/* */
/**************************************************************************/
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.2.1 */
/* 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 */
/* */
/* 03-08-2023 Xiuwen Cai Initial Version 6.2.1 */
/* */
/**************************************************************************/
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.2.1 */
/* 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 */
/* */
/* 03-08-2023 Xiuwen Cai Initial Version 6.2.1 */
/* */
/**************************************************************************/
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);
}
@@ -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.2.1 */
/* 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,106 +69,98 @@
/* */
/* 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 */
/* 03-08-2023 Xiuwen Cai Initial Version 6.2.1 */
/* */
/**************************************************************************/
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));
/* 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 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, 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)
/* 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++)
{
/* 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)
/* 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)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, 0);
/* Return the error... no point in continuing. */
/* Return error status. */
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));
/* 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;
/* Check for an error from flash driver. */
if (status)
/* 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, 0);
/* Return error status. */
return(status);
}
}
+166
View File
@@ -0,0 +1,166 @@
/**************************************************************************/
/* */
/* 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.2.1 */
/* 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 */
/* */
/* 03-08-2023 Xiuwen Cai Initial Version 6.2.1 */
/* */
/**************************************************************************/
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. */
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
status = (nand_flash -> lx_nand_flash_driver_pages_write)(nand_flash, block, page, main_buffer, spare_buffer_ptr, 1);
#else
status = (nand_flash -> lx_nand_flash_driver_pages_write)(block, page, main_buffer, spare_buffer_ptr, 1);
#endif
/* 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. */
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
status = (nand_flash -> lx_nand_flash_driver_pages_write)(nand_flash, block, page, main_buffer, spare_buffer_ptr, 1);
#else
status = (nand_flash -> lx_nand_flash_driver_pages_write)(block, page, main_buffer, spare_buffer_ptr, 1);
#endif
/* 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);
}
File diff suppressed because it is too large Load Diff
+9 -40
View File
@@ -40,7 +40,7 @@
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_partial_defragment PORTABLE C */
/* 6.1.7 */
/* 6.2.1 */
/* 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 */
/* 03-08-2023 Xiuwen Cai Modified comment(s), */
/* deprecated this API, */
/* resulting in version 6.2.1 */
/* */
/**************************************************************************/
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
}
}
+119 -51
View File
@@ -40,10 +40,10 @@
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_sector_read PORTABLE C */
/* 6.1.7 */
/* 6.2.1 */
/* 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 */
/* 03-08-2023 Xiuwen Cai Initial Version 6.2.1 */
/* */
/**************************************************************************/
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,137 @@ 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);
status = _lx_nand_flash_block_find(nand_flash, logical_sector, &block, &block_status);
/* Determine if the logical sector mapping was found. */
if (found_page)
/* Check return status. */
if (status != LX_SUCCESS)
{
/* Yes, we were able to find the logical sector to page mapping. */
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, 0);
/* 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);
/* Determine if the error is fatal. */
if (status != LX_NAND_ERROR_CORRECTED)
{
#ifdef LX_THREAD_SAFE_ENABLE
/* Check for an error from flash driver. */
if (status)
/* 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)
{
/* 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)
{
/* 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)
/* 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. */
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
status = (nand_flash -> lx_nand_flash_driver_pages_read)(nand_flash, block, (ULONG)page, (UCHAR*)buffer, spare_buffer_ptr, 1);
#else
status = (nand_flash -> lx_nand_flash_driver_pages_read)(block, (ULONG)page, (UCHAR*)buffer, spare_buffer_ptr, 1);
#endif
/* Change the status to LX_SUCCESS. */
status = LX_SUCCESS;
}
else
{
/* Check for an error from flash driver. */
if (status)
{
/* Adjust return status. */
status = LX_ERROR;
/* 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. */
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
status = (nand_flash -> lx_nand_flash_driver_pages_read)(nand_flash, block, logical_sector % nand_flash -> lx_nand_flash_pages_per_block, (UCHAR*)buffer, spare_buffer_ptr, 1);
#else
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);
#endif
/* 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++)
{
/* 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;
}
/* Set the status to success. */
status = LX_SUCCESS;
/* 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. */
+371 -156
View File
@@ -40,10 +40,10 @@
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_sector_release PORTABLE C */
/* 6.1.7 */
/* 6.2.1 */
/* 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 */
/* 03-08-2023 Xiuwen Cai Initial Version 6.2.1 */
/* */
/**************************************************************************/
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. */
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, 0);
/* Determine if this sector is the current maximum sector. */
if (nand_flash -> lx_nand_flash_max_mapped_sector == logical_sector)
/* 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,347 @@ 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. */
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
status = (nand_flash -> lx_nand_flash_driver_pages_read)(nand_flash, block, (ULONG)page, LX_NULL, spare_buffer_ptr, 1);
#else
status = (nand_flash -> lx_nand_flash_driver_pages_read)(block, (ULONG)page, LX_NULL, spare_buffer_ptr, 1);
#endif
/* 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. */
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
status = (nand_flash -> lx_nand_flash_driver_pages_write)(nand_flash, block, available_pages, (UCHAR*)nand_flash -> lx_nand_flash_page_buffer, spare_buffer_ptr, 1);
#else
status = (nand_flash -> lx_nand_flash_driver_pages_write)(block, available_pages, (UCHAR*)nand_flash -> lx_nand_flash_page_buffer, spare_buffer_ptr, 1);
#endif
/* 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. */
+289 -314
View File
@@ -40,10 +40,10 @@
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_sector_write PORTABLE C */
/* 6.1.7 */
/* 6.2.1 */
/* 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 */
/* 03-08-2023 Xiuwen Cai Initial Version 6.2.1 */
/* */
/**************************************************************************/
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. */
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, 0);
/* Determine if this is the new maximum mapped sector. */
if (logical_sector > nand_flash -> lx_nand_flash_max_mapped_sector)
/* 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);
}
/* Return error. */
return(status);
}
/* 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));
/* Check return status. */
else if (status != LX_SUCCESS)
{
/* 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));
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, new_block, 0);
/* Check for an error from flash driver. */
if (status)
/* 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,250 @@ 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)
/* Check if the block is full. */
if (block_status & LX_NAND_BLOCK_STATUS_FULL)
{
/* 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);
/* Set copy block flag. */
copy_block = LX_TRUE;
}
/* 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)))
{
/* 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
}
}
/* Indicate the write was successful. */
status = LX_SUCCESS;
/* Set update mapping flag. */
update_mapping = LX_TRUE;
}
else
{
/* Indicate the write was unsuccessful. */
status = LX_NO_SECTORS;
/* Set new block to the same as old block. */
new_block = block;
new_block_status = block_status;
}
/* 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. */
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
status = (nand_flash -> lx_nand_flash_driver_pages_write)(nand_flash, new_block, page, (UCHAR*)buffer, spare_buffer_ptr, 1);
#else
status = (nand_flash -> lx_nand_flash_driver_pages_write)(new_block, page, (UCHAR*)buffer, spare_buffer_ptr, 1);
#endif
/* 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
+106
View File
@@ -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.2.1 */
/* 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 */
/* */
/* 03-08-2023 Xiuwen Cai Initial Version 6.2.1 */
/* */
/**************************************************************************/
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);
}
+104
View File
@@ -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.2.1 */
/* 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 */
/* */
/* 03-08-2023 Xiuwen Cai Initial Version 6.2.1 */
/* */
/**************************************************************************/
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);
}
+107
View File
@@ -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.2.1 */
/* 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 */
/* */
/* 03-08-2023 Xiuwen Cai Initial Version 6.2.1 */
/* */
/**************************************************************************/
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);
}
+271 -18
View File
@@ -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:
@@ -99,19 +105,40 @@ ULONG *nand_flash_memory;
UINT _lx_nand_flash_simulator_initialize(LX_NAND_FLASH *nand_flash);
UINT _lx_nand_flash_simulator_erase_all(VOID);
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
UINT _lx_nand_flash_simulator_read(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page, ULONG *destination, ULONG words);
UINT _lx_nand_flash_simulator_write(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page, ULONG *source, ULONG words);
UINT _lx_nand_flash_simulator_block_erase(LX_NAND_FLASH *nand_flash, ULONG block, ULONG erase_count);
UINT _lx_nand_flash_simulator_block_erased_verify(LX_NAND_FLASH *nand_flash, ULONG block);
UINT _lx_nand_flash_simulator_page_erased_verify(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page);
UINT _lx_nand_flash_simulator_block_status_get(LX_NAND_FLASH *nand_flash, ULONG block, UCHAR *bad_block_byte);
UINT _lx_nand_flash_simulator_block_status_set(LX_NAND_FLASH *nand_flash, ULONG block, UCHAR bad_block_byte);
UINT _lx_nand_flash_simulator_extra_bytes_get(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page, UCHAR *destination, UINT size);
UINT _lx_nand_flash_simulator_extra_bytes_set(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page, UCHAR *source, UINT size);
UINT _lx_nand_flash_simulator_system_error(LX_NAND_FLASH *nand_flash, UINT error_code, ULONG block, ULONG page);
UINT _lx_nand_flash_simulator_pages_read(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page, UCHAR* main_buffer, UCHAR* spare_buffer, ULONG pages);
UINT _lx_nand_flash_simulator_pages_write(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page, UCHAR* main_buffer, UCHAR* spare_buffer, ULONG pages);
UINT _lx_nand_flash_simulator_pages_copy(LX_NAND_FLASH *nand_flash, ULONG source_block, ULONG source_page, ULONG destination_block, ULONG destination_page, ULONG pages, UCHAR* data_buffer);
#else
UINT _lx_nand_flash_simulator_read(ULONG block, ULONG page, ULONG *destination, ULONG words);
UINT _lx_nand_flash_simulator_write(ULONG block, ULONG page, ULONG *source, ULONG words);
UINT _lx_nand_flash_simulator_block_erase(ULONG block, ULONG erase_count);
UINT _lx_nand_flash_simulator_block_erased_verify(ULONG block);
UINT _lx_nand_flash_simulator_page_erased_verify(ULONG block, ULONG page);
UINT _lx_nand_flash_simulator_erase_all(VOID);
UINT _lx_nand_flash_simulator_block_status_get(ULONG block, UCHAR *bad_block_byte);
UINT _lx_nand_flash_simulator_block_status_set(ULONG block, UCHAR bad_block_byte);
UINT _lx_nand_flash_simulator_extra_bytes_get(ULONG block, ULONG page, UCHAR *destination, UINT size);
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);
#endif
UINT _lx_nand_flash_simulator_page_ecc_check(ULONG block, ULONG page);
UINT _lx_nand_flash_simulator_initialize(LX_NAND_FLASH *nand_flash)
{
@@ -136,19 +163,76 @@ 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;
}
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
UINT _lx_nand_flash_simulator_read(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page, ULONG *destination, ULONG words)
#else
UINT _lx_nand_flash_simulator_read(ULONG block, ULONG page, ULONG *destination, ULONG words)
#endif
{
ULONG *flash_address;
UINT status;
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
LX_PARAMETER_NOT_USED(nand_flash);
#endif
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,11 +244,55 @@ ULONG *flash_address;
*destination++ = *flash_address++;
}
return(LX_SUCCESS);
return(status);
}
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
UINT _lx_nand_flash_simulator_pages_read(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page, UCHAR* main_buffer, UCHAR* spare_buffer, ULONG pages)
#else
UINT _lx_nand_flash_simulator_pages_read(ULONG block, ULONG page, UCHAR* main_buffer, UCHAR* spare_buffer, ULONG pages)
#endif
{
UINT i;
UINT status;
UINT ecc_status = LX_SUCCESS;
for (i = 0; i < pages; i++)
{
if (main_buffer)
{
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
status = _lx_nand_flash_simulator_read(nand_flash, block, page + i, (ULONG*)(main_buffer + i * BYTES_PER_PHYSICAL_PAGE), WORDS_PER_PHYSICAL_PAGE);
#else
status = _lx_nand_flash_simulator_read(block, page + i, (ULONG*)(main_buffer + i * BYTES_PER_PHYSICAL_PAGE), WORDS_PER_PHYSICAL_PAGE);
#endif
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;
}
}
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
status = _lx_nand_flash_simulator_extra_bytes_get(nand_flash, block, page + i, spare_buffer + i * SPARE_BYTES_PER_PAGE, SPARE_BYTES_PER_PAGE);
#else
status = _lx_nand_flash_simulator_extra_bytes_get(block, page + i, spare_buffer + i * SPARE_BYTES_PER_PAGE, SPARE_BYTES_PER_PAGE);
#endif
}
return (ecc_status);
}
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
UINT _lx_nand_flash_simulator_write(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page, ULONG *source, ULONG words)
#else
UINT _lx_nand_flash_simulator_write(ULONG block, ULONG page, ULONG *source, ULONG words)
#endif
{
ULONG *flash_address;
@@ -176,6 +304,10 @@ UCHAR *new_ecc_buffer_ptr = new_ecc_buffer;
UCHAR *ecc_buffer_ptr = new_ecc_buffer_ptr;
ULONG *page_ptr = &(nand_memory_area[block].physical_pages[page].memory[0]);
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
LX_PARAMETER_NOT_USED(nand_flash);
#endif
/* Increment the diag info. */
nand_block_diag[block].page_writes[page]++;
if (nand_block_diag[block].page_writes[page] > nand_block_diag[block].max_page_writes[page])
@@ -210,7 +342,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,7 +367,76 @@ ULONG *page_ptr = &(nand_memory_area[block].physical_pages[page].memory[0]);
return(LX_SUCCESS);
}
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
UINT _lx_nand_flash_simulator_pages_write(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page, UCHAR* main_buffer, UCHAR* spare_buffer, ULONG pages)
#else
UINT _lx_nand_flash_simulator_pages_write(ULONG block, ULONG page, UCHAR* main_buffer, UCHAR* spare_buffer, ULONG pages)
#endif
{
UINT i;
UINT status = LX_SUCCESS;
for (i = 0; i < pages; i++)
{
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
_lx_nand_flash_simulator_extra_bytes_set(nand_flash, block, page + i, spare_buffer + i * SPARE_BYTES_PER_PAGE, SPARE_BYTES_PER_PAGE);
status = _lx_nand_flash_simulator_write(nand_flash, block, page + i, (ULONG*)(main_buffer + i * BYTES_PER_PHYSICAL_PAGE), WORDS_PER_PHYSICAL_PAGE);
#else
_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);
#endif
if (status == LX_INVALID_WRITE)
{
break;
}
}
return (status);
}
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
UINT _lx_nand_flash_simulator_pages_copy(LX_NAND_FLASH *nand_flash, ULONG source_block, ULONG source_page, ULONG destination_block, ULONG destination_page, ULONG pages, UCHAR *data_buffer)
#else
UINT _lx_nand_flash_simulator_pages_copy(ULONG source_block, ULONG source_page, ULONG destination_block, ULONG destination_page, ULONG pages, UCHAR *data_buffer)
#endif
{
UINT i;
UINT status = LX_SUCCESS;
for (i = 0; i < pages; i++)
{
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
status = _lx_nand_flash_simulator_pages_read(nand_flash, source_block, source_page + i, data_buffer, data_buffer + BYTES_PER_PHYSICAL_PAGE, 1);
#else
status = _lx_nand_flash_simulator_pages_read(source_block, source_page + i, data_buffer, data_buffer + BYTES_PER_PHYSICAL_PAGE, 1);
#endif
if (status != LX_SUCCESS && status != LX_NAND_ERROR_CORRECTED)
{
break;
}
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
status = _lx_nand_flash_simulator_pages_write(nand_flash, destination_block, destination_page + i, data_buffer, data_buffer + BYTES_PER_PHYSICAL_PAGE, 1);
#else
status = _lx_nand_flash_simulator_pages_write(destination_block, destination_page + i, data_buffer, data_buffer + BYTES_PER_PHYSICAL_PAGE, 1);
#endif
if (status != LX_SUCCESS)
{
break;
}
}
return (status);
}
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
UINT _lx_nand_flash_simulator_block_erase(LX_NAND_FLASH *nand_flash, ULONG block, ULONG erase_count)
#else
UINT _lx_nand_flash_simulator_block_erase(ULONG block, ULONG erase_count)
#endif
{
ULONG *pointer;
@@ -243,6 +444,9 @@ ULONG words;
UINT i;
LX_PARAMETER_NOT_USED(erase_count);
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
LX_PARAMETER_NOT_USED(nand_flash);
#endif
/* Increment the diag info. */
nand_block_diag[block].erases++;
@@ -285,7 +489,7 @@ UINT i, j;
pointer = (ULONG *) &nand_memory_area[0];
/* Loop to erase block. */
words = sizeof(nand_memory_area)/sizeof(ULONG);
words = sizeof(nand_memory_area)/(sizeof(ULONG));
while (words--)
{
@@ -297,12 +501,20 @@ UINT i, j;
}
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
UINT _lx_nand_flash_simulator_block_erased_verify(LX_NAND_FLASH *nand_flash, ULONG block)
#else
UINT _lx_nand_flash_simulator_block_erased_verify(ULONG block)
#endif
{
ULONG *word_ptr;
ULONG words;
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
LX_PARAMETER_NOT_USED(nand_flash);
#endif
/* Determine if the block is completely erased. */
/* Pickup the pointer to the first word of the block. */
@@ -324,13 +536,20 @@ ULONG words;
return(LX_SUCCESS);
}
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
UINT _lx_nand_flash_simulator_page_erased_verify(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page)
#else
UINT _lx_nand_flash_simulator_page_erased_verify(ULONG block, ULONG page)
#endif
{
ULONG *word_ptr;
ULONG words;
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
LX_PARAMETER_NOT_USED(nand_flash);
#endif
/* Determine if the block is completely erased. */
/* Pickup the pointer to the first word of the block's page. */
@@ -352,10 +571,17 @@ ULONG words;
return(LX_SUCCESS);
}
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
UINT _lx_nand_flash_simulator_block_status_get(LX_NAND_FLASH *nand_flash, ULONG block, UCHAR *bad_block_byte)
#else
UINT _lx_nand_flash_simulator_block_status_get(ULONG block, UCHAR *bad_block_byte)
#endif
{
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
LX_PARAMETER_NOT_USED(nand_flash);
#endif
/* Pickup the bad block byte and return it. */
*bad_block_byte = nand_memory_area[block].physical_pages[0].spare[BAD_BLOCK_POSITION];
@@ -363,9 +589,17 @@ UINT _lx_nand_flash_simulator_block_status_get(ULONG block, UCHAR *bad_block_by
return(LX_SUCCESS);
}
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
UINT _lx_nand_flash_simulator_block_status_set(LX_NAND_FLASH *nand_flash, ULONG block, UCHAR bad_block_byte)
#else
UINT _lx_nand_flash_simulator_block_status_set(ULONG block, UCHAR bad_block_byte)
#endif
{
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
LX_PARAMETER_NOT_USED(nand_flash);
#endif
/* Set the bad block byte. */
nand_memory_area[block].physical_pages[0].spare[BAD_BLOCK_POSITION] = bad_block_byte;
@@ -374,12 +608,18 @@ UINT _lx_nand_flash_simulator_block_status_set(ULONG block, UCHAR bad_block_byt
}
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
UINT _lx_nand_flash_simulator_extra_bytes_get(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page, UCHAR *destination, UINT size)
#else
UINT _lx_nand_flash_simulator_extra_bytes_get(ULONG block, ULONG page, UCHAR *destination, UINT size)
#endif
{
UCHAR *source;
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
LX_PARAMETER_NOT_USED(nand_flash);
#endif
/* Setup source pointer in the spare area. */
source = (UCHAR *) &(nand_memory_area[block].physical_pages[page].spare[EXTRA_BYTE_POSITION]);
@@ -396,12 +636,18 @@ UCHAR *source;
return(LX_SUCCESS);
}
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
UINT _lx_nand_flash_simulator_extra_bytes_set(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page, UCHAR *source, UINT size)
#else
UINT _lx_nand_flash_simulator_extra_bytes_set(ULONG block, ULONG page, UCHAR *source, UINT size)
#endif
{
UCHAR *destination;
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
LX_PARAMETER_NOT_USED(nand_flash);
#endif
/* Increment the diag info. */
nand_block_diag[block].page_writes[page]++;
@@ -423,11 +669,18 @@ UCHAR *destination;
return(LX_SUCCESS);
}
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
UINT _lx_nand_flash_simulator_system_error(LX_NAND_FLASH *nand_flash, UINT error_code, ULONG block, ULONG page)
#else
UINT _lx_nand_flash_simulator_system_error(UINT error_code, ULONG block, ULONG page)
#endif
{
LX_PARAMETER_NOT_USED(error_code);
LX_PARAMETER_NOT_USED(block);
LX_PARAMETER_NOT_USED(page);
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
LX_PARAMETER_NOT_USED(nand_flash);
#endif
/* Custom processing goes here... all errors except for LX_NAND_ERROR_CORRECTED are fatal. */
return(LX_ERROR);
+8 -1
View File
@@ -40,7 +40,7 @@
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_system_error PORTABLE C */
/* 6.1.7 */
/* 6.2.1 */
/* 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 */
/* 03-08-2023 Xiuwen Cai Modified comment(s), */
/* added new driver interface, */
/* resulting in version 6.2.1 */
/* */
/**************************************************************************/
VOID _lx_nand_flash_system_error(LX_NAND_FLASH *nand_flash, UINT error_code, ULONG block, ULONG page)
@@ -105,7 +108,11 @@ VOID _lx_nand_flash_system_error(LX_NAND_FLASH *nand_flash, UINT error_code, UL
{
/* Yes, call the driver's system error handler. */
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
(nand_flash -> lx_nand_flash_driver_system_error)(nand_flash, error_code, block, page);
#else
(nand_flash -> lx_nand_flash_driver_system_error)(error_code, block, page);
#endif
}
}
+42 -1
View File
@@ -40,7 +40,7 @@
/* FUNCTION RELEASE */
/* */
/* _lx_nor_flash_block_reclaim PORTABLE C */
/* 6.1.7 */
/* 6.3.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
@@ -83,6 +83,11 @@
/* resulting in version 6.1 */
/* 06-02-2021 Bhupendra Naphade Modified comment(s), */
/* resulting in version 6.1.7 */
/* 10-31-2023 Xiuwen Cai Modified comment(s), */
/* added count for minimum */
/* erased blocks, added */
/* obsolete count cache, */
/* resulting in version 6.3.0 */
/* */
/**************************************************************************/
UINT _lx_nor_flash_block_reclaim(LX_NOR_FLASH *nor_flash)
@@ -157,6 +162,14 @@ UINT status;
return(status);
}
/* Determine if the erase count is at the minimum. */
if (erase_count == nor_flash -> lx_nor_flash_minimum_erase_count)
{
/* Yes, decrement the minimum erased block count. */
nor_flash -> lx_nor_flash_minimum_erased_blocks--;
}
/* Increment the erase count. */
erase_count++;
@@ -225,6 +238,16 @@ UINT status;
/* Update parameters of this flash. */
nor_flash -> lx_nor_flash_free_physical_sectors = nor_flash -> lx_nor_flash_free_physical_sectors + obsolete_sectors;
nor_flash -> lx_nor_flash_obsolete_physical_sectors = nor_flash -> lx_nor_flash_obsolete_physical_sectors - obsolete_sectors;
#ifdef LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE
/* Check if the block is cached by obsolete count cache. */
if (erase_block < nor_flash -> lx_nor_flash_extended_cache_obsolete_count_max_block)
{
/* Yes, clear the obsolete count for this block. */
nor_flash -> lx_nor_flash_extended_cache_obsolete_count[erase_block] = 0;
}
#endif
}
else
{
@@ -489,6 +512,14 @@ UINT status;
return(status);
}
/* Determine if the erase count is at the minimum. */
if (erase_count == nor_flash -> lx_nor_flash_minimum_erase_count)
{
/* Yes, decrement the minimum erased block count. */
nor_flash -> lx_nor_flash_minimum_erased_blocks--;
}
/* Increment the erase count. */
erase_count++;
@@ -557,6 +588,16 @@ UINT status;
/* Update parameters of this flash. */
nor_flash -> lx_nor_flash_free_physical_sectors = nor_flash -> lx_nor_flash_free_physical_sectors + obsolete_sectors;
nor_flash -> lx_nor_flash_obsolete_physical_sectors = nor_flash -> lx_nor_flash_obsolete_physical_sectors - obsolete_sectors;
#ifdef LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE
/* Check if the block is cached by obsolete count cache. */
if (erase_block < nor_flash -> lx_nor_flash_extended_cache_obsolete_count_max_block)
{
/* Yes, clear the obsolete count for this block. */
nor_flash -> lx_nor_flash_extended_cache_obsolete_count[erase_block] = 0;
}
#endif
}
}
+8 -1
View File
@@ -40,7 +40,7 @@
/* FUNCTION RELEASE */
/* */
/* _lx_nor_flash_driver_block_erase PORTABLE C */
/* 6.1.7 */
/* 6.2.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
@@ -76,6 +76,9 @@
/* resulting in version 6.1 */
/* 06-02-2021 Bhupendra Naphade Modified comment(s), */
/* resulting in version 6.1.7 */
/* 03-08-2023 Xiuwen Cai Modified comment(s), */
/* added new driver interface, */
/* resulting in version 6.2.1 */
/* */
/**************************************************************************/
UINT _lx_nor_flash_driver_block_erase(LX_NOR_FLASH *nor_flash, ULONG block, ULONG erase_count)
@@ -118,7 +121,11 @@ ULONG *cache_entry_end;
#endif
/* Call the actual driver block erase function. */
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
status = (nor_flash -> lx_nor_flash_driver_block_erase)(nor_flash, block, erase_count);
#else
status = (nor_flash -> lx_nor_flash_driver_block_erase)(block, erase_count);
#endif
/* Return completion status. */
return(status);
+19 -2
View File
@@ -39,8 +39,8 @@
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nor_flash_extended_cache_read PORTABLE C */
/* 6.1.7 */
/* _lx_nor_flash_extended_cache_read PORTABLE C */
/* 6.2.1 */
/* 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 */
/* 03-08-2023 Xiuwen Cai Modified comment(s), */
/* added new driver interface, */
/* resulting in version 6.2.1 */
/* */
/**************************************************************************/
UINT _lx_nor_flash_driver_read(LX_NOR_FLASH *nor_flash, ULONG *flash_address, ULONG *destination, ULONG words)
@@ -160,9 +163,15 @@ UINT least_used_cache_entry;
cache_entry_start = nor_flash -> lx_nor_flash_base_address + cache_offset;
/* Call the actual driver read function. */
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
status = (nor_flash -> lx_nor_flash_driver_read)(nor_flash, cache_entry_start,
nor_flash -> lx_nor_flash_extended_cache[least_used_cache_entry].lx_nor_flash_extended_cache_entry_sector_memory,
LX_NOR_SECTOR_SIZE);
#else
status = (nor_flash -> lx_nor_flash_driver_read)(cache_entry_start,
nor_flash -> lx_nor_flash_extended_cache[least_used_cache_entry].lx_nor_flash_extended_cache_entry_sector_memory,
LX_NOR_SECTOR_SIZE);
#endif
/* Determine if there was an error. */
if (status != LX_SUCCESS)
@@ -191,7 +200,11 @@ UINT least_used_cache_entry;
{
/* Call the actual driver read function. */
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
status = (nor_flash -> lx_nor_flash_driver_read)(nor_flash, flash_address, destination, words);
#else
status = (nor_flash -> lx_nor_flash_driver_read)(flash_address, destination, words);
#endif
/* Return completion status. */
return(status);
@@ -201,7 +214,11 @@ UINT status;
/* Call the actual driver read function. */
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
status = (nor_flash -> lx_nor_flash_driver_read)(nor_flash, flash_address, destination, words);
#else
status = (nor_flash -> lx_nor_flash_driver_read)(flash_address, destination, words);
#endif
/* Return completion status. */
return(status);
+12 -1
View File
@@ -40,7 +40,7 @@
/* FUNCTION RELEASE */
/* */
/* _lx_nor_flash_driver_write PORTABLE C */
/* 6.1.7 */
/* 6.2.1 */
/* 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 */
/* 03-08-2023 Xiuwen Cai Modified comment(s), */
/* added new driver interface, */
/* resulting in version 6.2.1 */
/* */
/**************************************************************************/
UINT _lx_nor_flash_driver_write(LX_NOR_FLASH *nor_flash, ULONG *flash_address, ULONG *source, ULONG words)
@@ -126,7 +129,11 @@ ULONG cache_offset;
}
/* In any case, call the actual driver write function. */
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
status = (nor_flash -> lx_nor_flash_driver_write)(nor_flash, flash_address, source, words);
#else
status = (nor_flash -> lx_nor_flash_driver_write)(flash_address, source, words);
#endif
/* Return completion status. */
return(status);
@@ -136,7 +143,11 @@ UINT status;
/* Call the actual driver write function. */
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
status = (nor_flash -> lx_nor_flash_driver_write)(nor_flash, flash_address, source, words);
#else
status = (nor_flash -> lx_nor_flash_driver_write)(flash_address, source, words);
#endif
/* Return completion status. */
return(status);
+172 -1
View File
@@ -40,7 +40,7 @@
/* FUNCTION RELEASE */
/* */
/* _lx_nor_flash_extended_cache_enable PORTABLE C */
/* 6.1.9 */
/* 6.3.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
@@ -84,6 +84,10 @@
/* added check for out of */
/* bound memory access, */
/* resulting in version 6.1.9 */
/* 10-31-2023 Xiuwen Cai Modified comment(s), */
/* added mapping bitmap cache, */
/* added obsolete count cache, */
/* resulting in version 6.3.0 */
/* */
/**************************************************************************/
UINT _lx_nor_flash_extended_cache_enable(LX_NOR_FLASH *nor_flash, VOID *memory, ULONG size)
@@ -93,6 +97,22 @@ UINT _lx_nor_flash_extended_cache_enable(LX_NOR_FLASH *nor_flash, VOID *memory,
UINT i;
ULONG cache_size;
ULONG *cache_memory;
#ifdef LX_NOR_ENABLE_MAPPING_BITMAP
ULONG mapping_bitmap_words;
ULONG mapping_bitmap_word;
ULONG logical_sector;
ULONG *mapping_bitmap_ptr;
#endif
#ifdef LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE
ULONG obsolete_count_words;
ULONG obsolete_sectors;
#endif
#if defined(LX_NOR_ENABLE_MAPPING_BITMAP) || defined(LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE)
ULONG *block_word_ptr;
UINT j;
UINT status;
ULONG block_word;
#endif
/* Determine if memory was specified but with an invalid size (less than one NOR sector). */
@@ -118,6 +138,157 @@ ULONG *cache_memory;
/* Setup cache memory pointer. */
cache_memory = (ULONG *) memory;
#if defined(LX_NOR_ENABLE_MAPPING_BITMAP) || defined(LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE)
/* Check if the NOR flash is opened. */
if (nor_flash -> lx_nor_flash_state == LX_NOR_FLASH_OPENED)
{
#if defined(LX_NOR_ENABLE_MAPPING_BITMAP)
/* Get the mapping bitmap cache size. */
mapping_bitmap_words = (nor_flash -> lx_nor_flash_total_physical_sectors + 31) / 32;
/* Check if the mapping bitmap cache fits in the suppiled cache memory. */
if (cache_size < mapping_bitmap_words)
{
/* Update the cache size. */
mapping_bitmap_words = cache_size;
}
/* Setup the mapping bitmap cache. */
nor_flash -> lx_nor_flash_extended_cache_mapping_bitmap = cache_memory;
/* Setup the mapping bitmap cache size. */
nor_flash -> lx_nor_flash_extended_cache_mapping_bitmap_max_logical_sector = mapping_bitmap_words * 32;
/* Clear the mapping bitmap cache. */
for (i = 0; i < mapping_bitmap_words; i++)
{
cache_memory[i] = 0;
}
/* Update the cache memory pointer. */
mapping_bitmap_ptr = cache_memory;
/* Update the cache size. */
cache_size = cache_size - mapping_bitmap_words;
/* Update the cache memory pointer. */
cache_memory = cache_memory + mapping_bitmap_words;
#endif
#if defined(LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE)
/* Get the obsolete count cache size. */
obsolete_count_words = nor_flash -> lx_nor_flash_total_blocks * sizeof(LX_NOR_OBSOLETE_COUNT_CACHE_TYPE) / 4;
/* Check if the obsolete count cache fits in the suppiled cache memory. */
if (cache_size < obsolete_count_words)
{
/* Update the cache size. */
obsolete_count_words = cache_size;
}
/* Setup the obsolete count cache. */
nor_flash -> lx_nor_flash_extended_cache_obsolete_count = (LX_NOR_OBSOLETE_COUNT_CACHE_TYPE*)cache_memory;
/* Setup the obsolete count cache size. */
nor_flash -> lx_nor_flash_extended_cache_obsolete_count_max_block = obsolete_count_words * 4 / sizeof(LX_NOR_OBSOLETE_COUNT_CACHE_TYPE);
/* Update the cache size. */
cache_size = cache_size - obsolete_count_words;
/* Update the cache memory pointer. */
cache_memory = cache_memory + obsolete_count_words;
#endif
/* Loop through the blocks. */
for (i = 0; i < nor_flash -> lx_nor_flash_total_blocks; i++)
{
/* Setup the block word pointer to the first word of the block. */
block_word_ptr = (nor_flash -> lx_nor_flash_base_address + (i * nor_flash -> lx_nor_flash_words_per_block));
#if defined(LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE)
/* Initialize the obsolete count cache. */
obsolete_sectors = 0;
#endif
/* Now walk the list of logical-physical sector mapping. */
for (j = 0; j < nor_flash ->lx_nor_flash_physical_sectors_per_block; j++)
{
/* Read this word of the sector mapping list. */
#ifdef LX_DIRECT_READ
/* Read the word directly. */
block_word = *(block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + j);
#else
status = _lx_nor_flash_driver_read(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + j), &block_word, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return an error. */
return(LX_ERROR);
}
#endif
/* Determine if the entry hasn't been used. */
if (block_word == LX_NOR_PHYSICAL_SECTOR_FREE)
{
break;
}
/* Is this entry valid? */
if ((block_word & (LX_NOR_PHYSICAL_SECTOR_VALID | LX_NOR_PHYSICAL_SECTOR_MAPPING_NOT_VALID)) == LX_NOR_PHYSICAL_SECTOR_VALID)
{
#if defined(LX_NOR_ENABLE_MAPPING_BITMAP)
/* Yes, get the logical sector. */
logical_sector = block_word & LX_NOR_LOGICAL_SECTOR_MASK;
/* Get the mapping bitmap word. */
mapping_bitmap_word = logical_sector >> 5;
/* Check if the mapping bitmap word is within the cache. */
if (mapping_bitmap_word < mapping_bitmap_words)
{
/* Set the bit in the mapping bitmap. */
mapping_bitmap_ptr[mapping_bitmap_word] |= (ULONG)(1 << (logical_sector & 31));
}
#endif
}
else
{
#if defined(LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE)
/* Increment the obsolete sector count. */
obsolete_sectors++;
#endif
}
}
#if defined(LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE)
/* Check if the block is cached by obsolete count cache. */
if (i < nor_flash -> lx_nor_flash_extended_cache_obsolete_count_max_block)
{
/* Yes, cache the obsolete sector count. */
nor_flash -> lx_nor_flash_extended_cache_obsolete_count[i] = (LX_NOR_OBSOLETE_COUNT_CACHE_TYPE)obsolete_sectors;
}
#endif
}
}
#endif
/* Loop through the memory supplied and assign to cache entries. */
i = 0;
while (cache_size >= LX_NOR_SECTOR_SIZE)
+137 -35
View File
@@ -40,7 +40,7 @@
/* FUNCTION RELEASE */
/* */
/* _lx_nor_flash_logical_sector_find PORTABLE C */
/* 6.1.7 */
/* 6.3.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
@@ -70,6 +70,7 @@
/* CALLS */
/* */
/* _lx_nor_flash_driver_read Driver flash sector read */
/* _lx_nor_flash_driver_write Driver flash sector write */
/* _lx_nor_flash_system_error Internal system error handler */
/* */
/* CALLED BY */
@@ -85,6 +86,12 @@
/* resulting in version 6.1 */
/* 06-02-2021 Bhupendra Naphade Modified comment(s), */
/* resulting in version 6.1.7 */
/* 10-31-2023 Xiuwen Cai Modified comment(s), */
/* added mapping bitmap cache, */
/* added obsolete count cache, */
/* optimized full obsoleted */
/* block searching logic, */
/* resulting in version 6.3.0 */
/* */
/**************************************************************************/
UINT _lx_nor_flash_logical_sector_find(LX_NOR_FLASH *nor_flash, ULONG logical_sector, ULONG superceded_check, ULONG **physical_sector_map_entry, ULONG **physical_sector_address)
@@ -102,7 +109,10 @@ ULONG i, j;
ULONG search_start;
LX_NOR_SECTOR_MAPPING_CACHE_ENTRY *sector_mapping_cache_entry_ptr = LX_NULL;
LX_NOR_SECTOR_MAPPING_CACHE_ENTRY temp_sector_mapping_cache_entry;
#ifndef LX_DIRECT_READ
#ifndef LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE
ULONG valid_sector_found;
#endif
#if !defined(LX_DIRECT_READ) || !defined(LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE)
UINT status;
#endif
@@ -119,6 +129,24 @@ UINT status;
return(LX_SECTOR_NOT_FOUND);
}
#ifndef LX_NOR_DISABLE_EXTENDED_CACHE
#ifdef LX_NOR_ENABLE_MAPPING_BITMAP
/* Determine if the logical sector is in the range of mapping bitmap cache. */
if (logical_sector < nor_flash -> lx_nor_flash_extended_cache_mapping_bitmap_max_logical_sector)
{
/* Determine if the logical sector is mapped. */
if ((nor_flash -> lx_nor_flash_extended_cache_mapping_bitmap[logical_sector >> 5] & (ULONG)(1 << (logical_sector & 31))) == 0)
{
/* Not mapped, return not found. */
return(LX_SECTOR_NOT_FOUND);
}
}
#endif
#endif
/* Determine if the sector mapping cache is enabled. */
if (nor_flash -> lx_nor_flash_sector_mapping_cache_enabled)
{
@@ -224,6 +252,36 @@ UINT status;
while (total_blocks--)
{
#ifdef LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE
/* Determine if the obsolete sector count is available in the cache. */
if (i < nor_flash -> lx_nor_flash_extended_cache_obsolete_count_max_block)
{
/* Check if the block contains obsolete sectors only. */
if ((ULONG)nor_flash -> lx_nor_flash_extended_cache_obsolete_count[i] == nor_flash -> lx_nor_flash_physical_sectors_per_block)
{
/* Move to the next block. */
i++;
/* Determine if we have wrapped. */
if (i >= nor_flash -> lx_nor_flash_total_blocks)
{
/* Yes, we have wrapped, set to block 0. */
i = 0;
}
/* Start at the first sector in the next block. */
j = 0;
/* No point in looking further into this block, just continue the loop. */
continue;
}
}
#endif
/* Setup the block word pointer to the first word of the search block. */
block_word_ptr = (nor_flash -> lx_nor_flash_base_address + (i * nor_flash -> lx_nor_flash_words_per_block));
@@ -249,51 +307,67 @@ UINT status;
return(status);
}
#endif
/* Is the value valid? */
if (min_logical_sector != LX_ALL_ONES)
{
#ifdef LX_DIRECT_READ
/* Read the word directly. */
max_logical_sector = *(block_word_ptr + LX_NOR_FLASH_MAX_LOGICAL_SECTOR_OFFSET);
/* Read the word directly. */
max_logical_sector = *(block_word_ptr + LX_NOR_FLASH_MAX_LOGICAL_SECTOR_OFFSET);
#else
status = _lx_nor_flash_driver_read(nor_flash, block_word_ptr + LX_NOR_FLASH_MAX_LOGICAL_SECTOR_OFFSET, &max_logical_sector, 1);
status = _lx_nor_flash_driver_read(nor_flash, block_word_ptr + LX_NOR_FLASH_MAX_LOGICAL_SECTOR_OFFSET, &max_logical_sector, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
#endif
/* Are the values valid? */
if ((min_logical_sector != LX_ALL_ONES) && (max_logical_sector != LX_ALL_ONES))
{
/* Now let's check to see if the search sector is within this range. */
if ((logical_sector < min_logical_sector) || (logical_sector > max_logical_sector))
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Move to the next block. */
i++;
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Determine if we have wrapped. */
if (i >= nor_flash -> lx_nor_flash_total_blocks)
/* Return the error. */
return(status);
}
#endif
/* Is the value valid? */
if (max_logical_sector != LX_ALL_ONES)
{
/* Now let's check to see if the search sector is within this range. */
if ((logical_sector < min_logical_sector) || (logical_sector > max_logical_sector))
{
/* Yes, we have wrapped, set to block 0. */
i = 0;
/* Move to the next block. */
i++;
/* Determine if we have wrapped. */
if (i >= nor_flash -> lx_nor_flash_total_blocks)
{
/* Yes, we have wrapped, set to block 0. */
i = 0;
}
/* Start at the first sector in the next block. */
j = 0;
/* No point in looking further into this block, just continue the loop. */
continue;
}
/* Start at the first sector in the next block. */
j = 0;
/* No point in looking further into this block, just continue the loop. */
continue;
}
}
else
{
/* Set the max logical sector to all ones. */
max_logical_sector = LX_ALL_ONES;
}
#ifndef LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE
/* Clear the valid sector found flag. */
valid_sector_found = LX_FALSE;
#endif
/* Setup the total number of sectors. */
total_sectors = nor_flash -> lx_nor_flash_physical_sectors_per_block;
@@ -440,6 +514,11 @@ UINT status;
return(LX_SUCCESS);
}
}
#ifndef LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE
/* Set the valid sector found flag. */
valid_sector_found = LX_TRUE;
#endif
}
/* Move to the next list entry. */
@@ -453,6 +532,29 @@ UINT status;
j = 0;
}
}
#ifndef LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE
/* Check if the block contains no valid sectors. */
if ((valid_sector_found == LX_FALSE) && (max_logical_sector != LX_ALL_ONES))
{
/* Clear max logical sector to indicate sectors are all obsoleted. */
max_logical_sector = 0;
/* Write the max logical sector to the block header. */
status = _lx_nor_flash_driver_write(nor_flash, block_word_ptr + LX_NOR_FLASH_MAX_LOGICAL_SECTOR_OFFSET, &max_logical_sector, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
}
#endif
/* Determine if there are any more mapped sectors. */
if (mapped_sectors == 0)
@@ -40,7 +40,7 @@
/* FUNCTION RELEASE */
/* */
/* _lx_nor_flash_next_block_to_erase_find PORTABLE C */
/* 6.1.7 */
/* 6.3.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
@@ -81,6 +81,12 @@
/* resulting in version 6.1 */
/* 06-02-2021 Bhupendra Naphade Modified comment(s), */
/* resulting in version 6.1.7 */
/* 10-31-2023 Xiuwen Cai Modified comment(s), */
/* added mapping bitmap cache, */
/* added obsolete count cache, */
/* optimized full obsoleted */
/* block searching logic, */
/* resulting in version 6.3.0 */
/* */
/**************************************************************************/
UINT _lx_nor_flash_next_block_to_erase_find(LX_NOR_FLASH *nor_flash, ULONG *return_erase_block, ULONG *return_erase_count, ULONG *return_mapped_sectors, ULONG *return_obsolete_sectors)
@@ -97,16 +103,23 @@ ULONG min_block_erase = 0;
ULONG min_block_erase_count;
ULONG min_block_obsolete_count = 0;
ULONG min_block_mapped_count = 0;
ULONG min_block_mapped_count_available = LX_FALSE;
ULONG max_obsolete_sectors;
ULONG max_obsolete_block = 0;
ULONG max_obsolete_erase_count = 0;
ULONG max_obsolete_mapped_count = 0;
ULONG max_obsolete_mapped_count_available = LX_FALSE;
ULONG min_system_block_erase_count;
ULONG system_min_erased_blocks;
ULONG max_system_block_erase_count;
ULONG erase_count_threshold;
ULONG min_logical_sector;
ULONG max_logical_sector;
#ifndef LX_DIRECT_READ
UINT status;
#endif
UINT obsolete_sectors_available;
UINT mapped_sectors_available;
/* Setup the block word pointer to the first word of the search block. */
@@ -117,6 +130,7 @@ UINT status;
/* Initialize the system minimum and maximum erase counts. */
min_system_block_erase_count = LX_ALL_ONES;
system_min_erased_blocks = 0;
max_system_block_erase_count = 0;
/* Initialize the maximum obsolete sector count. */
@@ -161,16 +175,263 @@ UINT status;
#endif
/* Update the system minimum and maximum erase counts. */
if (erase_count == min_system_block_erase_count)
{
system_min_erased_blocks ++;
}
if (erase_count < min_system_block_erase_count)
{
min_system_block_erase_count = erase_count;
system_min_erased_blocks = 1;
}
if (erase_count > max_system_block_erase_count)
max_system_block_erase_count = erase_count;
/* Initialize the obsolete and mapped sector count available flags. */
obsolete_sectors_available = LX_FALSE;
mapped_sectors_available = LX_FALSE;
#ifdef LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE
/* Determine if the obsolete sector count is available in the cache. */
if (i < nor_flash -> lx_nor_flash_extended_cache_obsolete_count_max_block)
{
/* Yes, the obsolete sector count is available. */
obsolete_sectors_available = LX_TRUE;
/* Pickup the obsolete sector count from the cache. */
obsolete_sectors = (ULONG)nor_flash -> lx_nor_flash_extended_cache_obsolete_count[i];
}
else
{
#endif
/* Read the minimum and maximum logical sector values in this block. */
#ifdef LX_DIRECT_READ
/* Read the word directly. */
min_logical_sector = *(block_word_ptr + LX_NOR_FLASH_MIN_LOGICAL_SECTOR_OFFSET);
#else
status = _lx_nor_flash_driver_read(nor_flash, block_word_ptr + LX_NOR_FLASH_MIN_LOGICAL_SECTOR_OFFSET, &min_logical_sector, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
#endif
/* Determine if the minimum logical sector is valid. */
if (min_logical_sector != LX_ALL_ONES)
{
#ifdef LX_DIRECT_READ
/* Read the word directly. */
max_logical_sector = *(block_word_ptr + LX_NOR_FLASH_MAX_LOGICAL_SECTOR_OFFSET);
#else
status = _lx_nor_flash_driver_read(nor_flash, block_word_ptr + LX_NOR_FLASH_MAX_LOGICAL_SECTOR_OFFSET, &max_logical_sector, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
#endif
/* Are the values valid? */
/* Now let's check to see if all the sector are obsoleted. */
if ((max_logical_sector != LX_ALL_ONES) && (max_logical_sector < min_logical_sector))
{
obsolete_sectors_available = LX_TRUE;
obsolete_sectors = nor_flash -> lx_nor_flash_physical_sectors_per_block;
}
}
#ifdef LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE
}
#endif
/* Determine if the mapped sector count is available. */
if (obsolete_sectors_available == LX_FALSE)
{
/* Compute the number of obsolete and mapped sectors for this block. */
/* Initialize the obsolete and mapped sector counts. */
obsolete_sectors = 0;
mapped_sectors = 0;
/* Set the mapped sector count and obsolete sector count available flags. */
mapped_sectors_available = LX_TRUE;
obsolete_sectors_available = LX_TRUE;
/* Setup a pointer to the mapped list. */
list_word_ptr = block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset;
/* Loop through the mapped list for this block. */
for (j = 0; j < nor_flash -> lx_nor_flash_physical_sectors_per_block; j++)
{
/* Read the current mapping entry. */
#ifdef LX_DIRECT_READ
/* Read the word directly. */
list_word = *(list_word_ptr);
#else
status = _lx_nor_flash_driver_read(nor_flash, list_word_ptr, &list_word, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
#endif
/* Determine if the entry hasn't been used. */
if (list_word == LX_NOR_PHYSICAL_SECTOR_FREE)
{
/* Since allocations are done sequentially in the block, we know nothing
else exists after this point. */
break;
}
/* Is this entry obsolete? */
if ((list_word & LX_NOR_PHYSICAL_SECTOR_VALID) == 0)
{
/* Increment the number of obsolete sectors. */
obsolete_sectors++;
}
else
{
/* Increment the number of mapped sectors. */
mapped_sectors++;
}
/* Move the list pointer ahead. */
list_word_ptr++;
}
}
/* Determine if this block contains full obsoleted sectors and the erase count is minimum. */
if ((obsolete_sectors == nor_flash -> lx_nor_flash_physical_sectors_per_block) &&
(erase_count == nor_flash -> lx_nor_flash_minimum_erase_count) &&
(nor_flash -> lx_nor_flash_minimum_erased_blocks > 0))
{
/* Yes, we have a full obsoleted block with minimum erase count. */
*return_erase_block = i;
*return_erase_count = erase_count;
*return_obsolete_sectors = obsolete_sectors;
*return_mapped_sectors = mapped_sectors;
break;
}
/* Determine if we have a block with a new maximum number of obsolete sectors. */
if ((obsolete_sectors > max_obsolete_sectors) && (erase_count <= erase_count_threshold))
{
/* Update the new maximum obsolete sectors and related information. */
max_obsolete_sectors = obsolete_sectors;
max_obsolete_block = i;
max_obsolete_erase_count = erase_count;
max_obsolete_mapped_count = mapped_sectors;
max_obsolete_mapped_count_available = mapped_sectors_available;
}
else if ((max_obsolete_sectors) && (obsolete_sectors == max_obsolete_sectors) && (erase_count <= erase_count_threshold))
{
/* Another block has the same number of obsolete sectors. Does this new block have a smaller erase
count? */
if (erase_count < max_obsolete_erase_count)
{
/* Yes, erase the block with the smaller erase count. */
max_obsolete_sectors = obsolete_sectors;
max_obsolete_block = i;
max_obsolete_erase_count = erase_count;
max_obsolete_mapped_count = mapped_sectors;
max_obsolete_mapped_count_available = mapped_sectors_available;
}
}
/* 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 = i;
min_block_obsolete_count = obsolete_sectors;
min_block_mapped_count = mapped_sectors;
min_block_mapped_count_available = mapped_sectors_available;
}
/* Move to the next block. */
block_word_ptr = block_word_ptr + nor_flash -> lx_nor_flash_words_per_block;
}
/* Determine if we found a block with full obsoleted sector and the erase count is minimum. */
if (i == nor_flash -> lx_nor_flash_total_blocks)
{
/* Determine if we can erase the block with the most obsolete sectors. */
if (max_obsolete_sectors)
{
/* Erase the block with the most obsolete sectors. */
*return_erase_block = max_obsolete_block;
*return_erase_count = max_obsolete_erase_count;
*return_obsolete_sectors = max_obsolete_sectors;
*return_mapped_sectors = max_obsolete_mapped_count;
mapped_sectors_available = max_obsolete_mapped_count_available;
}
else
{
/* Otherwise, choose the block with the smallest erase count. */
*return_erase_block = min_block_erase;
*return_erase_count = min_block_erase_count;
*return_obsolete_sectors = min_block_obsolete_count;
*return_mapped_sectors = min_block_mapped_count;
mapped_sectors_available = min_block_mapped_count_available;
}
/* Update the overall minimum and maximum erase count. */
nor_flash -> lx_nor_flash_minimum_erase_count = min_system_block_erase_count;
nor_flash -> lx_nor_flash_minimum_erased_blocks = system_min_erased_blocks;
nor_flash -> lx_nor_flash_maximum_erase_count = max_system_block_erase_count;
}
/* Determine if the mapped sector count is available. */
if (mapped_sectors_available == LX_FALSE)
{
/* Compute the number of obsolete and mapped sectors for this block. */
obsolete_sectors = 0;
mapped_sectors = 0;
mapped_sectors = 0;
/* Setup a pointer to the mapped list. */
block_word_ptr = nor_flash -> lx_nor_flash_base_address + *return_erase_block * nor_flash -> lx_nor_flash_words_per_block;
list_word_ptr = block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset;
/* Loop through the mapped list for this block. */
@@ -202,18 +463,12 @@ UINT status;
{
/* Since allocations are done sequentially in the block, we know nothing
else exists after this point. */
else exists after this point. */
break;
}
/* Is this entry obsolete? */
if ((list_word & LX_NOR_PHYSICAL_SECTOR_VALID) == 0)
{
/* Increment the number of obsolete sectors. */
obsolete_sectors++;
}
else
/* Is this entry mapped? */
if ((list_word & LX_NOR_PHYSICAL_SECTOR_VALID) != 0)
{
/* Increment the number of mapped sectors. */
@@ -224,71 +479,10 @@ UINT status;
list_word_ptr++;
}
/* Determine if we have a block with a new maximum number of obsolete sectors. */
if ((obsolete_sectors > max_obsolete_sectors) && (erase_count <= erase_count_threshold))
{
/* Return the mapped sector count. */
*return_mapped_sectors = mapped_sectors;
/* Update the new maximum obsolete sectors and related information. */
max_obsolete_sectors = obsolete_sectors;
max_obsolete_block = i;
max_obsolete_erase_count = erase_count;
max_obsolete_mapped_count = mapped_sectors;
}
else if ((max_obsolete_sectors) && (obsolete_sectors == max_obsolete_sectors) && (erase_count <= erase_count_threshold))
{
/* Another block has the same number of obsolete sectors. Does this new block have a smaller erase
count? */
if (erase_count < max_obsolete_erase_count)
{
/* Yes, erase the block with the smaller erase count. */
max_obsolete_sectors = obsolete_sectors;
max_obsolete_block = i;
max_obsolete_erase_count = erase_count;
max_obsolete_mapped_count = mapped_sectors;
}
}
/* 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 = i;
min_block_obsolete_count = obsolete_sectors;
min_block_mapped_count = mapped_sectors;
}
/* Move to the next block. */
block_word_ptr = block_word_ptr + nor_flash -> lx_nor_flash_words_per_block;
}
/* Determine if we can erase the block with the most obsolete sectors. */
if (max_obsolete_sectors)
{
/* Erase the block with the most obsolete sectors. */
*return_erase_block = max_obsolete_block;
*return_erase_count = max_obsolete_erase_count;
*return_obsolete_sectors = max_obsolete_sectors;
*return_mapped_sectors = max_obsolete_mapped_count;
}
else
{
/* Otherwise, choose the block with the smallest erase count. */
*return_erase_block = min_block_erase;
*return_erase_count = min_block_erase_count;
*return_obsolete_sectors = min_block_obsolete_count;
*return_mapped_sectors = min_block_mapped_count;
}
/* Update the overall minimum and maximum erase count. */
nor_flash -> lx_nor_flash_minimum_erase_count = min_system_block_erase_count;
nor_flash -> lx_nor_flash_maximum_erase_count = max_system_block_erase_count;
/* Return success. */
return(LX_SUCCESS);
}
+33 -4
View File
@@ -40,7 +40,7 @@
/* FUNCTION RELEASE */
/* */
/* _lx_nor_flash_open PORTABLE C */
/* 6.1.7 */
/* 6.3.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
@@ -92,6 +92,17 @@
/* 06-02-2021 Bhupendra Naphade Modified comment(s), and */
/* updated product constants */
/* resulting in version 6.1.7 */
/* 03-08-2023 Xiuwen Cai Modified comment(s), */
/* added new driver interface, */
/* resulting in version 6.2.1 */
/* 10-31-2023 Xiuwen Cai Modified comment(s), */
/* added count for minimum */
/* erased blocks, added */
/* obsolete count cache, */
/* avoided clearing user */
/* extension in flash control */
/* block, */
/* resulting in version 6.3.0 */
/* */
/**************************************************************************/
UINT _lx_nor_flash_open(LX_NOR_FLASH *nor_flash, CHAR *name, UINT (*nor_driver_initialize)(LX_NOR_FLASH *))
@@ -109,7 +120,7 @@ ULONG free_sectors;
ULONG used_sectors;
ULONG *new_map_entry;
ULONG *new_sector_address;
ULONG erased_count, min_erased_count, max_erased_count, temp_erased_count;
ULONG erased_count, min_erased_count, max_erased_count, temp_erased_count, min_erased_blocks;
ULONG j, k, l;
UINT status;
#ifdef LX_FREE_SECTOR_DATA_VERIFY
@@ -121,8 +132,8 @@ LX_INTERRUPT_SAVE_AREA
LX_PARAMETER_NOT_USED(name);
/* Clear the NOR flash control block. */
LX_MEMSET(nor_flash, 0, sizeof(LX_NOR_FLASH));
/* Clear the NOR flash control block. User extension is not cleared. */
LX_MEMSET(nor_flash, 0, (ULONG)((UCHAR*)&(nor_flash -> lx_nor_flash_open_previous) - (UCHAR*)nor_flash) + sizeof(nor_flash -> lx_nor_flash_open_previous));
/* Call the flash driver's initialization function. */
(nor_driver_initialize)(nor_flash);
@@ -210,6 +221,7 @@ LX_INTERRUPT_SAVE_AREA
/* Setup default values for the max/min erased counts. */
min_erased_count = LX_ALL_ONES;
min_erased_blocks = 0;
max_erased_count = 0;
/* Setup the block word pointer to the first word of the first block, which is effectively the
@@ -252,12 +264,23 @@ LX_INTERRUPT_SAVE_AREA
/* No, valid block. Isolate the erased count. */
erased_count = (block_word & LX_BLOCK_ERASE_COUNT_MASK);
/* Is the erased count the minimum? */
if (erased_count == min_erased_count)
{
/* Yes, increment the minimum erased block count. */
min_erased_blocks++;
}
/* Is this the new minimum? */
if (erased_count < min_erased_count)
{
/* Yes, remember the new minimum. */
min_erased_count = erased_count;
/* Reset the minimum erased block count. */
min_erased_blocks = 1;
}
/* Is this the new maximum? */
@@ -324,6 +347,7 @@ LX_INTERRUPT_SAVE_AREA
/* Update the overall minimum and maximum erase count. */
nor_flash -> lx_nor_flash_minimum_erase_count = 1;
nor_flash -> lx_nor_flash_minimum_erased_blocks = nor_flash -> lx_nor_flash_total_blocks;
nor_flash -> lx_nor_flash_maximum_erase_count = 1;
/* Update the number of free physical sectors. */
@@ -393,7 +417,11 @@ LX_INTERRUPT_SAVE_AREA
nor_flash -> lx_nor_flash_diagnostic_erased_block++;
/* Check to see if the block is erased. */
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
status = (nor_flash -> lx_nor_flash_driver_block_erased_verify)(nor_flash, l);
#else
status = (nor_flash -> lx_nor_flash_driver_block_erased_verify)(l);
#endif
/* Is the block completely erased? */
if (status != LX_SUCCESS)
@@ -799,6 +827,7 @@ LX_INTERRUPT_SAVE_AREA
/* Update the overall minimum and maximum erase count. */
nor_flash -> lx_nor_flash_minimum_erase_count = min_erased_count;
nor_flash -> lx_nor_flash_minimum_erased_blocks = min_erased_blocks;
nor_flash -> lx_nor_flash_maximum_erase_count = max_erased_count;
/* Determine if we need to update the free sector search pointer. */
+16 -1
View File
@@ -40,7 +40,7 @@
/* FUNCTION RELEASE */
/* */
/* _lx_nor_flash_sector_read PORTABLE C */
/* 6.1.7 */
/* 6.3.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
@@ -84,6 +84,9 @@
/* resulting in version 6.1 */
/* 06-02-2021 Bhupendra Naphade Modified comment(s), */
/* resulting in version 6.1.7 */
/* 10-31-2023 Xiuwen Cai Modified comment(s), */
/* added mapping bitmap cache, */
/* resulting in version 6.3.0 */
/* */
/**************************************************************************/
UINT _lx_nor_flash_sector_read(LX_NOR_FLASH *nor_flash, ULONG logical_sector, VOID *buffer)
@@ -179,6 +182,18 @@ ULONG *sector_address;
/* Return status. */
return(LX_ERROR);
}
#ifndef LX_NOR_DISABLE_EXTENDED_CACHE
#ifdef LX_NOR_ENABLE_MAPPING_BITMAP
/* Determine if the logical sector is within the mapping bitmap. */
if (logical_sector < nor_flash -> lx_nor_flash_extended_cache_mapping_bitmap_max_logical_sector)
{
/* Set the bit in the mapping bitmap. */
nor_flash -> lx_nor_flash_extended_cache_mapping_bitmap[logical_sector >> 5] |= (ULONG)(1 << (logical_sector & 31));
}
#endif
#endif
/* Increment the number of mapped physical sectors. */
nor_flash -> lx_nor_flash_mapped_physical_sectors++;
+35 -1
View File
@@ -40,7 +40,7 @@
/* FUNCTION RELEASE */
/* */
/* _lx_nor_flash_sector_release PORTABLE C */
/* 6.1.7 */
/* 6.3.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
@@ -84,6 +84,10 @@
/* resulting in version 6.1 */
/* 06-02-2021 Bhupendra Naphade Modified comment(s), */
/* resulting in version 6.1.7 */
/* 10-31-2023 Xiuwen Cai Modified comment(s), */
/* added mapping bitmap cache, */
/* added obsolete count cache, */
/* resulting in version 6.3.0 */
/* */
/**************************************************************************/
UINT _lx_nor_flash_sector_release(LX_NOR_FLASH *nor_flash, ULONG logical_sector)
@@ -94,6 +98,9 @@ ULONG *mapping_address;
ULONG mapping_entry;
ULONG *sector_address;
ULONG i;
#ifdef LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE
ULONG block;
#endif
#ifdef LX_THREAD_SAFE_ENABLE
@@ -164,9 +171,36 @@ ULONG i;
return(LX_ERROR);
}
#ifndef LX_NOR_DISABLE_EXTENDED_CACHE
#ifdef LX_NOR_ENABLE_MAPPING_BITMAP
/* Determine if the logical sector is within the mapping bitmap. */
if (logical_sector < nor_flash -> lx_nor_flash_extended_cache_mapping_bitmap_max_logical_sector)
{
/* Set the bit in the mapping bitmap. */
nor_flash -> lx_nor_flash_extended_cache_mapping_bitmap[logical_sector >> 5] &= (ULONG)~(1 << (logical_sector & 31));
}
#endif
#endif
/* Increment the number of obsolete physical sectors. */
nor_flash -> lx_nor_flash_obsolete_physical_sectors++;
#ifdef LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE
/* Get the block number from mapping address. */
block = (ULONG)(mapping_address - nor_flash -> lx_nor_flash_base_address) / nor_flash -> lx_nor_flash_words_per_block;
/* Determine if this block is within the range of the obsolete count cache. */
if (block < nor_flash -> lx_nor_flash_extended_cache_obsolete_count_max_block)
{
/* Increment the obsolete count for this block. */
nor_flash -> lx_nor_flash_extended_cache_obsolete_count[block] ++;
}
#endif
/* Decrement the number of mapped physical sectors. */
nor_flash -> lx_nor_flash_mapped_physical_sectors--;
+34 -2
View File
@@ -40,7 +40,7 @@
/* FUNCTION RELEASE */
/* */
/* _lx_nor_flash_sector_write PORTABLE C */
/* 6.1.7 */
/* 6.3.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
@@ -87,6 +87,10 @@
/* resulting in version 6.1 */
/* 06-02-2021 Bhupendra Naphade Modified comment(s), */
/* resulting in version 6.1.7 */
/* 10-31-2023 Xiuwen Cai Modified comment(s), */
/* added mapping bitmap cache, */
/* added obsolete count cache, */
/* resulting in version 6.3.0 */
/* */
/**************************************************************************/
UINT _lx_nor_flash_sector_write(LX_NOR_FLASH *nor_flash, ULONG logical_sector, VOID *buffer)
@@ -101,7 +105,9 @@ ULONG new_mapping_entry;
ULONG i;
LX_NOR_SECTOR_MAPPING_CACHE_ENTRY *sector_mapping_cache_entry_ptr;
UINT status;
#ifdef LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE
ULONG block;
#endif
#ifdef LX_THREAD_SAFE_ENABLE
@@ -269,6 +275,18 @@ UINT status;
/* Return status. */
return(LX_ERROR);
}
#ifndef LX_NOR_DISABLE_EXTENDED_CACHE
#ifdef LX_NOR_ENABLE_MAPPING_BITMAP
/* Determine if the logical sector is within the mapping bitmap. */
if (logical_sector < nor_flash -> lx_nor_flash_extended_cache_mapping_bitmap_max_logical_sector)
{
/* Set the bit in the mapping bitmap. */
nor_flash -> lx_nor_flash_extended_cache_mapping_bitmap[logical_sector >> 5] |= (ULONG)(1 << (logical_sector & 31));
}
#endif
#endif
/* Increment the number of mapped physical sectors. */
nor_flash -> lx_nor_flash_mapped_physical_sectors++;
@@ -303,6 +321,20 @@ UINT status;
/* Increment the number of obsolete physical sectors. */
nor_flash -> lx_nor_flash_obsolete_physical_sectors++;
#ifdef LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE
/* Get the block number from mapping address. */
block = (ULONG)(old_mapping_address - nor_flash -> lx_nor_flash_base_address) / nor_flash -> lx_nor_flash_words_per_block;
/* Determine if this block is within the range of the obsolete count cache. */
if (block < nor_flash -> lx_nor_flash_extended_cache_obsolete_count_max_block)
{
/* Increment the obsolete count for this block. */
nor_flash -> lx_nor_flash_extended_cache_obsolete_count[block] ++;
}
#endif
/* Decrement the number of mapped physical sectors. */
nor_flash -> lx_nor_flash_mapped_physical_sectors--;
+49 -4
View File
@@ -60,13 +60,20 @@ FLASH_BLOCK nor_memory_area[TOTAL_BLOCKS];
ULONG nor_sector_memory[WORDS_PER_PHYSICAL_SECTOR];
UINT _lx_nor_flash_simulator_initialize(LX_NOR_FLASH *nor_flash);
UINT _lx_nor_flash_simulator_erase_all(VOID);
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
UINT _lx_nor_flash_simulator_read(LX_NOR_FLASH *nor_flash, ULONG *flash_address, ULONG *destination, ULONG words);
UINT _lx_nor_flash_simulator_write(LX_NOR_FLASH *nor_flash, ULONG *flash_address, ULONG *source, ULONG words);
UINT _lx_nor_flash_simulator_block_erase(LX_NOR_FLASH *nor_flash, ULONG block, ULONG erase_count);
UINT _lx_nor_flash_simulator_block_erased_verify(LX_NOR_FLASH *nor_flash, ULONG block);
UINT _lx_nor_flash_simulator_system_error(LX_NOR_FLASH *nor_flash, UINT error_code, ULONG block, ULONG sector);
#else
UINT _lx_nor_flash_simulator_read(ULONG *flash_address, ULONG *destination, ULONG words);
UINT _lx_nor_flash_simulator_write(ULONG *flash_address, ULONG *source, ULONG words);
UINT _lx_nor_flash_simulator_block_erase(ULONG block, ULONG erase_count);
UINT _lx_nor_flash_simulator_block_erased_verify(ULONG block);
UINT _lx_nor_flash_simulator_erase_all(VOID);
UINT _lx_nor_flash_simulator_system_error(UINT error_code, ULONG block, ULONG sector);
#endif
UINT _lx_nor_flash_simulator_initialize(LX_NOR_FLASH *nor_flash)
@@ -92,10 +99,17 @@ UINT _lx_nor_flash_simulator_initialize(LX_NOR_FLASH *nor_flash)
return(LX_SUCCESS);
}
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
UINT _lx_nor_flash_simulator_read(LX_NOR_FLASH *nor_flash, ULONG *flash_address, ULONG *destination, ULONG words)
#else
UINT _lx_nor_flash_simulator_read(ULONG *flash_address, ULONG *destination, ULONG words)
#endif
{
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
LX_PARAMETER_NOT_USED(nor_flash);
#endif
/* Loop to read flash. */
while (words--)
{
@@ -107,9 +121,17 @@ UINT _lx_nor_flash_simulator_read(ULONG *flash_address, ULONG *destination, ULO
}
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
UINT _lx_nor_flash_simulator_write(LX_NOR_FLASH *nor_flash, ULONG *flash_address, ULONG *source, ULONG words)
#else
UINT _lx_nor_flash_simulator_write(ULONG *flash_address, ULONG *source, ULONG words)
#endif
{
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
LX_PARAMETER_NOT_USED(nor_flash);
#endif
/* Loop to write flash. */
while (words--)
{
@@ -121,12 +143,19 @@ UINT _lx_nor_flash_simulator_write(ULONG *flash_address, ULONG *source, ULONG w
return(LX_SUCCESS);
}
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
UINT _lx_nor_flash_simulator_block_erase(LX_NOR_FLASH *nor_flash, ULONG block, ULONG erase_count)
#else
UINT _lx_nor_flash_simulator_block_erase(ULONG block, ULONG erase_count)
#endif
{
ULONG *pointer;
ULONG words;
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
LX_PARAMETER_NOT_USED(nor_flash);
#endif
LX_PARAMETER_NOT_USED(erase_count);
/* Setup pointer. */
@@ -156,7 +185,7 @@ ULONG words;
pointer = (ULONG *) &nor_memory_area[0];
/* Loop to erase block. */
words = sizeof(nor_memory_area)/sizeof(ULONG);
words = sizeof(nor_memory_area)/(sizeof(ULONG));
while (words--)
{
@@ -168,12 +197,20 @@ ULONG words;
}
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
UINT _lx_nor_flash_simulator_block_erased_verify(LX_NOR_FLASH *nor_flash, ULONG block)
#else
UINT _lx_nor_flash_simulator_block_erased_verify(ULONG block)
#endif
{
ULONG *word_ptr;
ULONG words;
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
LX_PARAMETER_NOT_USED(nor_flash);
#endif
/* Determine if the block is completely erased. */
/* Pickup the pointer to the first word of the block. */
@@ -195,8 +232,16 @@ ULONG words;
return(LX_SUCCESS);
}
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
UINT _lx_nor_flash_simulator_system_error(LX_NOR_FLASH *nor_flash, UINT error_code, ULONG block, ULONG sector)
#else
UINT _lx_nor_flash_simulator_system_error(UINT error_code, ULONG block, ULONG sector)
#endif
{
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
LX_PARAMETER_NOT_USED(nor_flash);
#endif
LX_PARAMETER_NOT_USED(error_code);
LX_PARAMETER_NOT_USED(block);
LX_PARAMETER_NOT_USED(sector);
+8 -1
View File
@@ -40,7 +40,7 @@
/* FUNCTION RELEASE */
/* */
/* _lx_nor_flash_system_error PORTABLE C */
/* 6.1.7 */
/* 6.2.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
@@ -75,6 +75,9 @@
/* resulting in version 6.1 */
/* 06-02-2021 Bhupendra Naphade Modified comment(s), */
/* resulting in version 6.1.7 */
/* 03-08-2023 Xiuwen Cai Modified comment(s), */
/* added new driver interface, */
/* resulting in version 6.2.1 */
/* */
/**************************************************************************/
VOID _lx_nor_flash_system_error(LX_NOR_FLASH *nor_flash, UINT error_code)
@@ -91,7 +94,11 @@ VOID _lx_nor_flash_system_error(LX_NOR_FLASH *nor_flash, UINT error_code)
{
/* Yes, call the driver's system error handler. */
#ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
(nor_flash -> lx_nor_flash_driver_system_error)(nor_flash, error_code);
#else
(nor_flash -> lx_nor_flash_driver_system_error)(error_code);
#endif
}
}