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.1.7        */
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 /*                                                                        */
91 /**************************************************************************/
_lx_nor_flash_sector_write(LX_NOR_FLASH * nor_flash,ULONG logical_sector,VOID * buffer)92 UINT  _lx_nor_flash_sector_write(LX_NOR_FLASH *nor_flash, ULONG logical_sector, VOID *buffer)
93 {
94 
95 ULONG                           *old_mapping_address;
96 ULONG                           *old_sector_address;
97 ULONG                           old_mapping_entry;
98 ULONG                           *new_mapping_address;
99 ULONG                           *new_sector_address;
100 ULONG                           new_mapping_entry;
101 ULONG                           i;
102 LX_NOR_SECTOR_MAPPING_CACHE_ENTRY  *sector_mapping_cache_entry_ptr;
103 UINT                            status;
104 
105 
106 #ifdef LX_THREAD_SAFE_ENABLE
107 
108     /* Obtain the thread safe mutex.  */
109     tx_mutex_get(&nor_flash -> lx_nor_flash_mutex, TX_WAIT_FOREVER);
110 #endif
111 
112     /* Determine if there are less than two block's worth of free sectors.  */
113     i =  0;
114     while (nor_flash -> lx_nor_flash_free_physical_sectors <= nor_flash -> lx_nor_flash_physical_sectors_per_block)
115     {
116 
117         /* Attempt to reclaim one physical block.  */
118         _lx_nor_flash_block_reclaim(nor_flash);
119 
120         /* Increment the block count.  */
121         i++;
122 
123         /* Have we exceeded the number of blocks in the system?  */
124         if (i >= nor_flash -> lx_nor_flash_total_blocks)
125         {
126 
127             /* Yes, break out of the loop.  */
128             break;
129         }
130     }
131 
132     /* Increment the number of write requests.  */
133     nor_flash -> lx_nor_flash_write_requests++;
134 
135     /* See if we can find the sector in the current mapping.  */
136     _lx_nor_flash_logical_sector_find(nor_flash, logical_sector, LX_FALSE, &old_mapping_address, &old_sector_address);
137 
138     /* Allocate a new physical sector for this write.  */
139     _lx_nor_flash_physical_sector_allocate(nor_flash, logical_sector, &new_mapping_address, &new_sector_address);
140 
141     /* Determine if the new sector allocation was successful.  */
142     if (new_mapping_address)
143     {
144 
145         /* Yes, we were able to allocate a new physical sector.  */
146 
147         /* Update the number of free physical sectors.  */
148         nor_flash -> lx_nor_flash_free_physical_sectors--;
149 
150         /* Write the sector data to the new physical sector.  */
151         status =  _lx_nor_flash_driver_write(nor_flash, new_sector_address, buffer, LX_NOR_SECTOR_SIZE);
152 
153         /* Check for an error from flash driver. Drivers should never return an error..  */
154         if (status)
155         {
156 
157             /* Call system error handler.  */
158             _lx_nor_flash_system_error(nor_flash, status);
159 
160 #ifdef LX_THREAD_SAFE_ENABLE
161 
162             /* Release the thread safe mutex.  */
163             tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
164 #endif
165 
166             /* Return status.  */
167             return(LX_ERROR);
168         }
169 
170         /* Was there a previously mapped sector?  */
171         if (old_mapping_address)
172         {
173 
174             /* Now deprecate the old sector mapping.  */
175 
176             /* Read in the old sector mapping.  */
177 #ifdef LX_DIRECT_READ
178 
179             /* Read the word directly.  */
180             old_mapping_entry =  *(old_mapping_address);
181 #else
182             status =  _lx_nor_flash_driver_read(nor_flash, old_mapping_address, &old_mapping_entry, 1);
183 
184             /* Check for an error from flash driver. Drivers should never return an error..  */
185             if (status)
186             {
187 
188                 /* Call system error handler.  */
189                 _lx_nor_flash_system_error(nor_flash, status);
190 
191 #ifdef LX_THREAD_SAFE_ENABLE
192 
193                 /* Release the thread safe mutex.  */
194                 tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
195 #endif
196 
197                 /* Return status.  */
198                 return(LX_ERROR);
199             }
200 #endif
201 
202             /* Clear bit 30, which indicates this sector is superceded.  */
203             old_mapping_entry =  old_mapping_entry & ~((ULONG) LX_NOR_PHYSICAL_SECTOR_SUPERCEDED);
204 
205             /* Write the value back to the flash to clear bit 30.  */
206             status =  _lx_nor_flash_driver_write(nor_flash, old_mapping_address, &old_mapping_entry, 1);
207 
208             /* Check for an error from flash driver. Drivers should never return an error..  */
209             if (status)
210             {
211 
212                 /* Call system error handler.  */
213                 _lx_nor_flash_system_error(nor_flash, status);
214 
215 #ifdef LX_THREAD_SAFE_ENABLE
216 
217                 /* Release the thread safe mutex.  */
218                 tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
219 #endif
220 
221                 /* Return status.  */
222                 return(LX_ERROR);
223             }
224         }
225 
226         /* Now build the new mapping entry - with the not valid bit set initially.  */
227         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;
228 
229         /* Write out the new mapping entry.  */
230         status =  _lx_nor_flash_driver_write(nor_flash, new_mapping_address, &new_mapping_entry, 1);
231 
232         /* Check for an error from flash driver. Drivers should never return an error..  */
233         if (status)
234         {
235 
236             /* Call system error handler.  */
237             _lx_nor_flash_system_error(nor_flash, status);
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(LX_ERROR);
247         }
248 
249         /* Now clear the not valid bit to make this sector mapping valid.  This is done because the writing of the extra bytes itself can
250            be interrupted and we need to make sure this can be detected when the flash is opened again.  */
251         new_mapping_entry =  new_mapping_entry & ~((ULONG) LX_NOR_PHYSICAL_SECTOR_MAPPING_NOT_VALID);
252 
253         /* Clear the not valid bit.  */
254         status =  _lx_nor_flash_driver_write(nor_flash, new_mapping_address, &new_mapping_entry, 1);
255 
256         /* Check for an error from flash driver. Drivers should never return an error..  */
257         if (status)
258         {
259 
260             /* Call system error handler.  */
261             _lx_nor_flash_system_error(nor_flash, status);
262 
263 #ifdef LX_THREAD_SAFE_ENABLE
264 
265             /* Release the thread safe mutex.  */
266             tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
267 #endif
268 
269             /* Return status.  */
270             return(LX_ERROR);
271         }
272 
273         /* Increment the number of mapped physical sectors.  */
274         nor_flash -> lx_nor_flash_mapped_physical_sectors++;
275 
276         /* Was there a previously mapped sector?  */
277         if (old_mapping_address)
278         {
279 
280             /* Now clear bit 31, which indicates this sector is now obsoleted.  */
281             old_mapping_entry =  old_mapping_entry & ~((ULONG) LX_NOR_PHYSICAL_SECTOR_VALID);
282 
283             /* Write the value back to the flash to clear bit 31.  */
284             status =  _lx_nor_flash_driver_write(nor_flash, old_mapping_address, &old_mapping_entry, 1);
285 
286             /* Check for an error from flash driver. Drivers should never return an error..  */
287             if (status)
288             {
289 
290                 /* Call system error handler.  */
291                 _lx_nor_flash_system_error(nor_flash, status);
292 
293 #ifdef LX_THREAD_SAFE_ENABLE
294 
295                 /* Release the thread safe mutex.  */
296                 tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
297 #endif
298 
299               /* Return status.  */
300                 return(LX_ERROR);
301             }
302 
303             /* Increment the number of obsolete physical sectors.  */
304             nor_flash -> lx_nor_flash_obsolete_physical_sectors++;
305 
306             /* Decrement the number of mapped physical sectors.  */
307             nor_flash -> lx_nor_flash_mapped_physical_sectors--;
308 
309             /* Invalidate the old sector mapping cache entry.  */
310             _lx_nor_flash_sector_mapping_cache_invalidate(nor_flash, logical_sector);
311         }
312 
313         /* Determine if the sector mapping cache is enabled.  */
314         if (nor_flash -> lx_nor_flash_sector_mapping_cache_enabled)
315         {
316 
317             /* Yes, sector mapping cache is enabled, place this sector information in the cache.  */
318 
319             /* Calculate the starting index of the sector mapping cache for this sector entry.  */
320             i =  (logical_sector & LX_NOR_SECTOR_MAPPING_CACHE_HASH_MASK) * LX_NOR_SECTOR_MAPPING_CACHE_DEPTH;
321 
322             /* Build a pointer to the cache entry.  */
323             sector_mapping_cache_entry_ptr =  &nor_flash -> lx_nor_flash_sector_mapping_cache[i];
324 
325             /* Move all the cache entries down so the oldest is at the bottom.  */
326             *(sector_mapping_cache_entry_ptr + 3) =  *(sector_mapping_cache_entry_ptr + 2);
327             *(sector_mapping_cache_entry_ptr + 2) =  *(sector_mapping_cache_entry_ptr + 1);
328             *(sector_mapping_cache_entry_ptr + 1) =  *(sector_mapping_cache_entry_ptr);
329 
330             /* Setup the new sector information in the cache.  */
331             sector_mapping_cache_entry_ptr -> lx_nor_sector_mapping_cache_logical_sector =             (logical_sector | LX_NOR_SECTOR_MAPPING_CACHE_ENTRY_VALID);
332             sector_mapping_cache_entry_ptr -> lx_nor_sector_mapping_cache_physical_sector_map_entry =  new_mapping_address;
333             sector_mapping_cache_entry_ptr -> lx_nor_sector_mapping_cache_physical_sector_address =    new_sector_address;
334         }
335 
336         /* Indicate the write was successful.  */
337         status =  LX_SUCCESS;
338     }
339     else
340     {
341 
342         /* Indicate the write was unsuccessful.  */
343         status =  LX_NO_SECTORS;
344     }
345 
346 #ifdef LX_THREAD_SAFE_ENABLE
347 
348     /* Release the thread safe mutex.  */
349     tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
350 #endif
351 
352     /* Return the completion status.  */
353     return(status);
354 }
355 
356 
357