1 /**************************************************************************/
2 /* */
3 /* Copyright (c) Microsoft Corporation. All rights reserved. */
4 /* */
5 /* This software is licensed under the Microsoft Software License */
6 /* Terms for Microsoft Azure RTOS. Full text of the license can be */
7 /* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
8 /* and in the root directory of this software. */
9 /* */
10 /**************************************************************************/
11
12
13 /**************************************************************************/
14 /**************************************************************************/
15 /** */
16 /** LevelX Component */
17 /** */
18 /** NOR Flash */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23 #define LX_SOURCE_CODE
24
25
26 /* Disable ThreadX error checking. */
27
28 #ifndef LX_DISABLE_ERROR_CHECKING
29 #define LX_DISABLE_ERROR_CHECKING
30 #endif
31
32
33 /* Include necessary system files. */
34
35 #include "lx_api.h"
36
37
38 /**************************************************************************/
39 /* */
40 /* FUNCTION RELEASE */
41 /* */
42 /* _lx_nor_flash_sector_write PORTABLE C */
43 /* 6.3.0 */
44 /* AUTHOR */
45 /* */
46 /* William E. Lamie, Microsoft Corporation */
47 /* */
48 /* DESCRIPTION */
49 /* */
50 /* This function writes a logical sector to the NOR flash. */
51 /* */
52 /* INPUT */
53 /* */
54 /* nor_flash NOR flash instance */
55 /* logical_sector Logical sector number */
56 /* buffer Pointer to buffer to write */
57 /* (the size is 512 bytes) */
58 /* */
59 /* OUTPUT */
60 /* */
61 /* return status */
62 /* */
63 /* CALLS */
64 /* */
65 /* _lx_nor_flash_driver_write Driver flash sector write */
66 /* _lx_nor_flash_driver_read Driver flash sector read */
67 /* _lx_nor_flash_block_reclaim Reclaim one flash block */
68 /* _lx_nor_flash_logical_sector_find Find logical sector */
69 /* _lx_nor_flash_physical_sector_allocate */
70 /* Allocate new physical sector */
71 /* _lx_nor_flash_sector_mapping_cache_invalidate */
72 /* Invalidate cache entry */
73 /* _lx_nor_flash_system_error Internal system error handler */
74 /* tx_mutex_get Get thread protection */
75 /* tx_mutex_put Release thread protection */
76 /* */
77 /* CALLED BY */
78 /* */
79 /* Application Code */
80 /* */
81 /* RELEASE HISTORY */
82 /* */
83 /* DATE NAME DESCRIPTION */
84 /* */
85 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
86 /* 09-30-2020 William E. Lamie Modified comment(s), */
87 /* resulting in version 6.1 */
88 /* 06-02-2021 Bhupendra Naphade Modified comment(s), */
89 /* resulting in version 6.1.7 */
90 /* 10-31-2023 Xiuwen Cai Modified comment(s), */
91 /* added mapping bitmap cache, */
92 /* added obsolete count cache, */
93 /* resulting in version 6.3.0 */
94 /* */
95 /**************************************************************************/
_lx_nor_flash_sector_write(LX_NOR_FLASH * nor_flash,ULONG logical_sector,VOID * buffer)96 UINT _lx_nor_flash_sector_write(LX_NOR_FLASH *nor_flash, ULONG logical_sector, VOID *buffer)
97 {
98
99 ULONG *old_mapping_address;
100 ULONG *old_sector_address;
101 ULONG old_mapping_entry;
102 ULONG *new_mapping_address;
103 ULONG *new_sector_address;
104 ULONG new_mapping_entry;
105 ULONG i;
106 LX_NOR_SECTOR_MAPPING_CACHE_ENTRY *sector_mapping_cache_entry_ptr;
107 UINT status;
108 #ifdef LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE
109 ULONG block;
110 #endif
111
112 #ifdef LX_THREAD_SAFE_ENABLE
113
114 /* Obtain the thread safe mutex. */
115 tx_mutex_get(&nor_flash -> lx_nor_flash_mutex, TX_WAIT_FOREVER);
116 #endif
117
118 /* Determine if there are less than two block's worth of free sectors. */
119 i = 0;
120 while (nor_flash -> lx_nor_flash_free_physical_sectors <= nor_flash -> lx_nor_flash_physical_sectors_per_block)
121 {
122
123 /* Attempt to reclaim one physical block. */
124 _lx_nor_flash_block_reclaim(nor_flash);
125
126 /* Increment the block count. */
127 i++;
128
129 /* Have we exceeded the number of blocks in the system? */
130 if (i >= nor_flash -> lx_nor_flash_total_blocks)
131 {
132
133 /* Yes, break out of the loop. */
134 break;
135 }
136 }
137
138 /* Increment the number of write requests. */
139 nor_flash -> lx_nor_flash_write_requests++;
140
141 /* See if we can find the sector in the current mapping. */
142 _lx_nor_flash_logical_sector_find(nor_flash, logical_sector, LX_FALSE, &old_mapping_address, &old_sector_address);
143
144 /* Allocate a new physical sector for this write. */
145 _lx_nor_flash_physical_sector_allocate(nor_flash, logical_sector, &new_mapping_address, &new_sector_address);
146
147 /* Determine if the new sector allocation was successful. */
148 if (new_mapping_address)
149 {
150
151 /* Yes, we were able to allocate a new physical sector. */
152
153 /* Update the number of free physical sectors. */
154 nor_flash -> lx_nor_flash_free_physical_sectors--;
155
156 /* Write the sector data to the new physical sector. */
157 status = _lx_nor_flash_driver_write(nor_flash, new_sector_address, buffer, LX_NOR_SECTOR_SIZE);
158
159 /* Check for an error from flash driver. Drivers should never return an error.. */
160 if (status)
161 {
162
163 /* Call system error handler. */
164 _lx_nor_flash_system_error(nor_flash, status);
165
166 #ifdef LX_THREAD_SAFE_ENABLE
167
168 /* Release the thread safe mutex. */
169 tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
170 #endif
171
172 /* Return status. */
173 return(LX_ERROR);
174 }
175
176 /* Was there a previously mapped sector? */
177 if (old_mapping_address)
178 {
179
180 /* Now deprecate the old sector mapping. */
181
182 /* Read in the old sector mapping. */
183 #ifdef LX_DIRECT_READ
184
185 /* Read the word directly. */
186 old_mapping_entry = *(old_mapping_address);
187 #else
188 status = _lx_nor_flash_driver_read(nor_flash, old_mapping_address, &old_mapping_entry, 1);
189
190 /* Check for an error from flash driver. Drivers should never return an error.. */
191 if (status)
192 {
193
194 /* Call system error handler. */
195 _lx_nor_flash_system_error(nor_flash, status);
196
197 #ifdef LX_THREAD_SAFE_ENABLE
198
199 /* Release the thread safe mutex. */
200 tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
201 #endif
202
203 /* Return status. */
204 return(LX_ERROR);
205 }
206 #endif
207
208 /* Clear bit 30, which indicates this sector is superceded. */
209 old_mapping_entry = old_mapping_entry & ~((ULONG) LX_NOR_PHYSICAL_SECTOR_SUPERCEDED);
210
211 /* Write the value back to the flash to clear bit 30. */
212 status = _lx_nor_flash_driver_write(nor_flash, old_mapping_address, &old_mapping_entry, 1);
213
214 /* Check for an error from flash driver. Drivers should never return an error.. */
215 if (status)
216 {
217
218 /* Call system error handler. */
219 _lx_nor_flash_system_error(nor_flash, status);
220
221 #ifdef LX_THREAD_SAFE_ENABLE
222
223 /* Release the thread safe mutex. */
224 tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
225 #endif
226
227 /* Return status. */
228 return(LX_ERROR);
229 }
230 }
231
232 /* Now build the new mapping entry - with the not valid bit set initially. */
233 new_mapping_entry = ((ULONG) LX_NOR_PHYSICAL_SECTOR_VALID) | ((ULONG) LX_NOR_PHYSICAL_SECTOR_SUPERCEDED) | ((ULONG) LX_NOR_PHYSICAL_SECTOR_MAPPING_NOT_VALID) | logical_sector;
234
235 /* Write out the new mapping entry. */
236 status = _lx_nor_flash_driver_write(nor_flash, new_mapping_address, &new_mapping_entry, 1);
237
238 /* Check for an error from flash driver. Drivers should never return an error.. */
239 if (status)
240 {
241
242 /* Call system error handler. */
243 _lx_nor_flash_system_error(nor_flash, status);
244
245 #ifdef LX_THREAD_SAFE_ENABLE
246
247 /* Release the thread safe mutex. */
248 tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
249 #endif
250
251 /* Return status. */
252 return(LX_ERROR);
253 }
254
255 /* Now clear the not valid bit to make this sector mapping valid. This is done because the writing of the extra bytes itself can
256 be interrupted and we need to make sure this can be detected when the flash is opened again. */
257 new_mapping_entry = new_mapping_entry & ~((ULONG) LX_NOR_PHYSICAL_SECTOR_MAPPING_NOT_VALID);
258
259 /* Clear the not valid bit. */
260 status = _lx_nor_flash_driver_write(nor_flash, new_mapping_address, &new_mapping_entry, 1);
261
262 /* Check for an error from flash driver. Drivers should never return an error.. */
263 if (status)
264 {
265
266 /* Call system error handler. */
267 _lx_nor_flash_system_error(nor_flash, status);
268
269 #ifdef LX_THREAD_SAFE_ENABLE
270
271 /* Release the thread safe mutex. */
272 tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
273 #endif
274
275 /* Return status. */
276 return(LX_ERROR);
277 }
278 #ifndef LX_NOR_DISABLE_EXTENDED_CACHE
279 #ifdef LX_NOR_ENABLE_MAPPING_BITMAP
280
281 /* Determine if the logical sector is within the mapping bitmap. */
282 if (logical_sector < nor_flash -> lx_nor_flash_extended_cache_mapping_bitmap_max_logical_sector)
283 {
284
285 /* Set the bit in the mapping bitmap. */
286 nor_flash -> lx_nor_flash_extended_cache_mapping_bitmap[logical_sector >> 5] |= (ULONG)(1 << (logical_sector & 31));
287 }
288 #endif
289 #endif
290
291 /* Increment the number of mapped physical sectors. */
292 nor_flash -> lx_nor_flash_mapped_physical_sectors++;
293
294 /* Was there a previously mapped sector? */
295 if (old_mapping_address)
296 {
297
298 /* Now clear bit 31, which indicates this sector is now obsoleted. */
299 old_mapping_entry = old_mapping_entry & ~((ULONG) LX_NOR_PHYSICAL_SECTOR_VALID);
300
301 /* Write the value back to the flash to clear bit 31. */
302 status = _lx_nor_flash_driver_write(nor_flash, old_mapping_address, &old_mapping_entry, 1);
303
304 /* Check for an error from flash driver. Drivers should never return an error.. */
305 if (status)
306 {
307
308 /* Call system error handler. */
309 _lx_nor_flash_system_error(nor_flash, status);
310
311 #ifdef LX_THREAD_SAFE_ENABLE
312
313 /* Release the thread safe mutex. */
314 tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
315 #endif
316
317 /* Return status. */
318 return(LX_ERROR);
319 }
320
321 /* Increment the number of obsolete physical sectors. */
322 nor_flash -> lx_nor_flash_obsolete_physical_sectors++;
323
324 #ifdef LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE
325
326 /* Get the block number from mapping address. */
327 block = (ULONG)(old_mapping_address - nor_flash -> lx_nor_flash_base_address) / nor_flash -> lx_nor_flash_words_per_block;
328
329 /* Determine if this block is within the range of the obsolete count cache. */
330 if (block < nor_flash -> lx_nor_flash_extended_cache_obsolete_count_max_block)
331 {
332
333 /* Increment the obsolete count for this block. */
334 nor_flash -> lx_nor_flash_extended_cache_obsolete_count[block] ++;
335 }
336 #endif
337
338 /* Decrement the number of mapped physical sectors. */
339 nor_flash -> lx_nor_flash_mapped_physical_sectors--;
340
341 /* Invalidate the old sector mapping cache entry. */
342 _lx_nor_flash_sector_mapping_cache_invalidate(nor_flash, logical_sector);
343 }
344
345 /* Determine if the sector mapping cache is enabled. */
346 if (nor_flash -> lx_nor_flash_sector_mapping_cache_enabled)
347 {
348
349 /* Yes, sector mapping cache is enabled, place this sector information in the cache. */
350
351 /* Calculate the starting index of the sector mapping cache for this sector entry. */
352 i = (logical_sector & LX_NOR_SECTOR_MAPPING_CACHE_HASH_MASK) * LX_NOR_SECTOR_MAPPING_CACHE_DEPTH;
353
354 /* Build a pointer to the cache entry. */
355 sector_mapping_cache_entry_ptr = &nor_flash -> lx_nor_flash_sector_mapping_cache[i];
356
357 /* Move all the cache entries down so the oldest is at the bottom. */
358 *(sector_mapping_cache_entry_ptr + 3) = *(sector_mapping_cache_entry_ptr + 2);
359 *(sector_mapping_cache_entry_ptr + 2) = *(sector_mapping_cache_entry_ptr + 1);
360 *(sector_mapping_cache_entry_ptr + 1) = *(sector_mapping_cache_entry_ptr);
361
362 /* Setup the new sector information in the cache. */
363 sector_mapping_cache_entry_ptr -> lx_nor_sector_mapping_cache_logical_sector = (logical_sector | LX_NOR_SECTOR_MAPPING_CACHE_ENTRY_VALID);
364 sector_mapping_cache_entry_ptr -> lx_nor_sector_mapping_cache_physical_sector_map_entry = new_mapping_address;
365 sector_mapping_cache_entry_ptr -> lx_nor_sector_mapping_cache_physical_sector_address = new_sector_address;
366 }
367
368 /* Indicate the write was successful. */
369 status = LX_SUCCESS;
370 }
371 else
372 {
373
374 /* Indicate the write was unsuccessful. */
375 status = LX_NO_SECTORS;
376 }
377
378 #ifdef LX_THREAD_SAFE_ENABLE
379
380 /* Release the thread safe mutex. */
381 tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
382 #endif
383
384 /* Return the completion status. */
385 return(status);
386 }
387
388
389