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