1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** LevelX Component */
16 /** */
17 /** NOR Flash */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 #define LX_SOURCE_CODE
23
24
25 /* Disable ThreadX error checking. */
26
27 #ifndef LX_DISABLE_ERROR_CHECKING
28 #define LX_DISABLE_ERROR_CHECKING
29 #endif
30
31
32 /* Include necessary system files. */
33
34 #include "lx_api.h"
35
36
37 /**************************************************************************/
38 /* */
39 /* FUNCTION RELEASE */
40 /* */
41 /* _lx_nor_flash_sector_release PORTABLE C */
42 /* 6.3.0 */
43 /* AUTHOR */
44 /* */
45 /* William E. Lamie, Microsoft Corporation */
46 /* */
47 /* DESCRIPTION */
48 /* */
49 /* This function releases a logical sector from being managed in the */
50 /* NOR flash. */
51 /* */
52 /* INPUT */
53 /* */
54 /* nor_flash NOR flash instance */
55 /* logical_sector Logical sector number */
56 /* */
57 /* OUTPUT */
58 /* */
59 /* return status */
60 /* */
61 /* CALLS */
62 /* */
63 /* _lx_nor_flash_driver_write Driver flash sector write */
64 /* _lx_nor_flash_driver_read Driver flash sector read */
65 /* _lx_nor_flash_block_reclaim Reclaim one flash block */
66 /* _lx_nor_flash_sector_mapping_cache_invalidate */
67 /* Invalidate cache entry */
68 /* _lx_nor_flash_logical_sector_find Find logical sector */
69 /* _lx_nor_flash_system_error Internal system error handler */
70 /* tx_mutex_get Get thread protection */
71 /* tx_mutex_put Release thread protection */
72 /* */
73 /* CALLED BY */
74 /* */
75 /* Application Code */
76 /* */
77 /* RELEASE HISTORY */
78 /* */
79 /* DATE NAME DESCRIPTION */
80 /* */
81 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
82 /* 09-30-2020 William E. Lamie Modified comment(s), */
83 /* resulting in version 6.1 */
84 /* 06-02-2021 Bhupendra Naphade Modified comment(s), */
85 /* resulting in version 6.1.7 */
86 /* 10-31-2023 Xiuwen Cai Modified comment(s), */
87 /* added mapping bitmap cache, */
88 /* added obsolete count cache, */
89 /* resulting in version 6.3.0 */
90 /* */
91 /**************************************************************************/
_lx_nor_flash_sector_release(LX_NOR_FLASH * nor_flash,ULONG logical_sector)92 UINT _lx_nor_flash_sector_release(LX_NOR_FLASH *nor_flash, ULONG logical_sector)
93 {
94
95 UINT status;
96 ULONG *mapping_address;
97 ULONG mapping_entry;
98 ULONG *sector_address;
99 ULONG i;
100 #ifdef LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE
101 ULONG block;
102 #endif
103
104
105 #ifdef LX_THREAD_SAFE_ENABLE
106
107 /* Obtain the thread safe mutex. */
108 tx_mutex_get(&nor_flash -> lx_nor_flash_mutex, TX_WAIT_FOREVER);
109 #endif
110
111 /* Increment the number of read requests. */
112 nor_flash -> lx_nor_flash_read_requests++;
113
114 /* See if we can find the sector in the current mapping. */
115 _lx_nor_flash_logical_sector_find(nor_flash, logical_sector, LX_FALSE, &mapping_address, §or_address);
116
117 /* Determine if the logical sector was found. */
118 if (mapping_address)
119 {
120
121 /* Yes, we were able to find the logical sector. */
122
123 /* Read in the old sector mapping. */
124 #ifdef LX_DIRECT_READ
125
126 /* Read the word directly. */
127 mapping_entry = *(mapping_address);
128 #else
129 status = _lx_nor_flash_driver_read(nor_flash, mapping_address, &mapping_entry, 1);
130
131 /* Check for an error from flash driver. Drivers should never return an error.. */
132 if (status)
133 {
134
135 /* Call system error handler. */
136 _lx_nor_flash_system_error(nor_flash, status);
137
138 #ifdef LX_THREAD_SAFE_ENABLE
139
140 /* Release the thread safe mutex. */
141 tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
142 #endif
143
144 /* Return status. */
145 return(LX_ERROR);
146 }
147 #endif
148
149 /* Mark this sector as invalid. */
150 /* Now clear bits 31 and 30, which indicates this sector is now obsoleted. */
151 mapping_entry = mapping_entry & ~(((ULONG) LX_NOR_PHYSICAL_SECTOR_VALID) | ((ULONG) LX_NOR_PHYSICAL_SECTOR_SUPERCEDED));
152
153 /* Write the value back to the flash to clear bits 31 & 30. */
154 status = _lx_nor_flash_driver_write(nor_flash, mapping_address, &mapping_entry, 1);
155
156 /* Check for an error from flash driver. Drivers should never return an error.. */
157 if (status)
158 {
159
160 /* Call system error handler. */
161 _lx_nor_flash_system_error(nor_flash, status);
162
163 #ifdef LX_THREAD_SAFE_ENABLE
164
165 /* Release the thread safe mutex. */
166 tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
167 #endif
168
169 /* Return status. */
170 return(LX_ERROR);
171 }
172
173 #ifndef LX_NOR_DISABLE_EXTENDED_CACHE
174 #ifdef LX_NOR_ENABLE_MAPPING_BITMAP
175
176 /* Determine if the logical sector is within the mapping bitmap. */
177 if (logical_sector < nor_flash -> lx_nor_flash_extended_cache_mapping_bitmap_max_logical_sector)
178 {
179
180 /* Set the bit in the mapping bitmap. */
181 nor_flash -> lx_nor_flash_extended_cache_mapping_bitmap[logical_sector >> 5] &= (ULONG)~(1 << (logical_sector & 31));
182 }
183 #endif
184 #endif
185
186 /* Increment the number of obsolete physical sectors. */
187 nor_flash -> lx_nor_flash_obsolete_physical_sectors++;
188
189 #ifdef LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE
190
191 /* Get the block number from mapping address. */
192 block = (ULONG)(mapping_address - nor_flash -> lx_nor_flash_base_address) / nor_flash -> lx_nor_flash_words_per_block;
193
194 /* Determine if this block is within the range of the obsolete count cache. */
195 if (block < nor_flash -> lx_nor_flash_extended_cache_obsolete_count_max_block)
196 {
197
198 /* Increment the obsolete count for this block. */
199 nor_flash -> lx_nor_flash_extended_cache_obsolete_count[block] ++;
200 }
201 #endif
202
203 /* Decrement the number of mapped physical sectors. */
204 nor_flash -> lx_nor_flash_mapped_physical_sectors--;
205
206 /* Ensure the sector mapping cache no longer has this sector. */
207 _lx_nor_flash_sector_mapping_cache_invalidate(nor_flash, logical_sector);
208
209 /* Determine if there are less than two block's worth of free sectors. */
210 i = 0;
211 while (nor_flash -> lx_nor_flash_free_physical_sectors <= nor_flash -> lx_nor_flash_physical_sectors_per_block)
212 {
213
214 /* Attempt to reclaim one physical block. */
215 _lx_nor_flash_block_reclaim(nor_flash);
216
217 /* Increment the block count. */
218 i++;
219
220 /* Have we exceeded the number of blocks in the system? */
221 if (i >= nor_flash -> lx_nor_flash_total_blocks)
222 {
223
224 /* Yes, break out of the loop. */
225 break;
226 }
227 }
228
229 /* Set the status to success. */
230 status = LX_SUCCESS;
231 }
232 else
233 {
234
235 /* Could not find the logical sector. */
236 status = LX_SECTOR_NOT_FOUND;
237 }
238
239 #ifdef LX_THREAD_SAFE_ENABLE
240
241 /* Release the thread safe mutex. */
242 tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
243 #endif
244
245 /* Return status. */
246 return(status);
247 }
248
249