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 /** NAND 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_nand_flash_sector_release PORTABLE C */
43 /* 6.2.1 */
44 /* AUTHOR */
45 /* */
46 /* Xiuwen Cai, Microsoft Corporation */
47 /* */
48 /* DESCRIPTION */
49 /* */
50 /* This function releases a logical sector from being managed in the */
51 /* NAND flash. */
52 /* */
53 /* INPUT */
54 /* */
55 /* nand_flash NAND flash instance */
56 /* logical_sector Logical sector number */
57 /* */
58 /* OUTPUT */
59 /* */
60 /* return status */
61 /* */
62 /* CALLS */
63 /* */
64 /* _lx_nand_flash_block_find Find the mapped block */
65 /* lx_nand_flash_driver_pages_read Read pages */
66 /* _lx_nand_flash_block_allocate Allocate block */
67 /* _lx_nand_flash_mapped_block_list_remove */
68 /* Remove mapped block */
69 /* _lx_nand_flash_data_page_copy Copy data pages */
70 /* _lx_nand_flash_free_block_list_add Add free block to list */
71 /* _lx_nand_flash_block_mapping_set Set block mapping */
72 /* _lx_nand_flash_driver_block_erase Erase block */
73 /* _lx_nand_flash_erase_count_set Set erase count */
74 /* _lx_nand_flash_block_data_move Move block data */
75 /* _lx_nand_flash_block_status_set Set block status */
76 /* _lx_nand_flash_mapped_block_list_add Add mapped block to list */
77 /* _lx_nand_flash_system_error Internal system error handler */
78 /* tx_mutex_get Get thread protection */
79 /* tx_mutex_put Release thread protection */
80 /* */
81 /* CALLED BY */
82 /* */
83 /* Application Code */
84 /* */
85 /* RELEASE HISTORY */
86 /* */
87 /* DATE NAME DESCRIPTION */
88 /* */
89 /* 03-08-2023 Xiuwen Cai Initial Version 6.2.1 */
90 /* */
91 /**************************************************************************/
_lx_nand_flash_sector_release(LX_NAND_FLASH * nand_flash,ULONG logical_sector)92 UINT _lx_nand_flash_sector_release(LX_NAND_FLASH *nand_flash, ULONG logical_sector)
93 {
94
95 UINT status;
96 ULONG block;
97 USHORT block_status;
98 UCHAR *spare_buffer_ptr;
99 ULONG available_pages;
100 LONG page;
101 UINT release_sector = LX_FALSE;
102 ULONG new_block;
103 USHORT new_block_status;
104
105 #ifdef LX_THREAD_SAFE_ENABLE
106
107 /* Obtain the thread safe mutex. */
108 tx_mutex_get(&nand_flash -> lx_nand_flash_mutex, TX_WAIT_FOREVER);
109 #endif
110
111 /* Increment the number of release requests. */
112 nand_flash -> lx_nand_flash_diagnostic_sector_release_requests++;
113
114
115 /* See if we can find the sector in the current mapping. */
116 status = _lx_nand_flash_block_find(nand_flash, logical_sector, &block, &block_status);
117
118 /* Check return status. */
119 if (status != LX_SUCCESS)
120 {
121
122 /* Call system error handler. */
123 _lx_nand_flash_system_error(nand_flash, status, block, 0);
124
125 /* Determine if the error is fatal. */
126 if (status != LX_NAND_ERROR_CORRECTED)
127 {
128 #ifdef LX_THREAD_SAFE_ENABLE
129
130 /* Release the thread safe mutex. */
131 tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
132 #endif
133
134 /* Return an error. */
135 return(LX_ERROR);
136 }
137 }
138
139 /* Determine if the block is mapped. */
140 if (block != LX_NAND_BLOCK_UNMAPPED)
141 {
142
143 /* Setup spare buffer pointer. */
144 spare_buffer_ptr = (UCHAR*)nand_flash -> lx_nand_flash_page_buffer;
145
146 /* Get available pages in this block. */
147 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;
148
149 /* Determine if the pages are recorded sequentially. */
150 if (block_status & LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL)
151 {
152
153 /* Loop to search the logical page. */
154 for (page = (LONG)available_pages - 1; page >= 0; page--)
155 {
156
157 /* Read a page. */
158 #ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
159 status = (nand_flash -> lx_nand_flash_driver_pages_read)(nand_flash, block, (ULONG)page, LX_NULL, spare_buffer_ptr, 1);
160 #else
161 status = (nand_flash -> lx_nand_flash_driver_pages_read)(block, (ULONG)page, LX_NULL, spare_buffer_ptr, 1);
162 #endif
163
164 /* Check for an error from flash driver. */
165 if (status)
166 {
167
168 /* Call system error handler. */
169 _lx_nand_flash_system_error(nand_flash, status, block, 0);
170 #ifdef LX_THREAD_SAFE_ENABLE
171
172 /* Release the thread safe mutex. */
173 tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
174 #endif
175
176 /* Return an error. */
177 return(LX_ERROR);
178 }
179
180 /* Get the logical sector number from spare bytes, and check if it matches the addressed sector number. */
181 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)
182 {
183
184 /* Make sure the sector is not released. */
185 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))
186 {
187
188 /* Set release sector flag. */
189 release_sector = LX_TRUE;
190 }
191 }
192 }
193 }
194 else
195 {
196
197 /* Check if the logical sector is available. */
198 if (logical_sector % nand_flash -> lx_nand_flash_pages_per_block < available_pages)
199 {
200
201 /* Set release sector flag. */
202 release_sector = LX_TRUE;
203 }
204 }
205
206 /* Determine if the sector needs to be released. */
207 if (release_sector)
208 {
209
210 /* Check if the block is full. */
211 if (block_status & LX_NAND_BLOCK_STATUS_FULL)
212 {
213
214 /* Allocate a new block. */
215 status = _lx_nand_flash_block_allocate(nand_flash, &new_block);
216
217 /* Check return status. */
218 if (status != LX_SUCCESS)
219 {
220 /* Call system error handler. */
221 _lx_nand_flash_system_error(nand_flash, status, new_block, 0);
222 #ifdef LX_THREAD_SAFE_ENABLE
223
224 /* Release the thread safe mutex. */
225 tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
226 #endif
227
228 /* Return an error. */
229 return(LX_ERROR);
230
231 }
232
233 /* Set new block status to allocated. */
234 new_block_status = LX_NAND_BLOCK_STATUS_ALLOCATED;
235
236 /* Remove the old block from mapped block list. */
237 _lx_nand_flash_mapped_block_list_remove(nand_flash, logical_sector / nand_flash -> lx_nand_flash_pages_per_block);
238
239 /* Copy valid sector to new block. */
240 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));
241
242 /* Check for an error from flash driver. */
243 if (status)
244 {
245
246 /* Call system error handler. */
247 _lx_nand_flash_system_error(nand_flash, status, new_block, 0);
248 #ifdef LX_THREAD_SAFE_ENABLE
249
250 /* Release the thread safe mutex. */
251 tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
252 #endif
253
254 /* Return an error. */
255 return(LX_ERROR);
256 }
257
258 /* Determine if there are sectors after the addressed sector need to be copied. */
259 if (logical_sector % nand_flash -> lx_nand_flash_pages_per_block < nand_flash -> lx_nand_flash_pages_per_block - 1)
260 {
261
262 /* Copy valid sector to new block. */
263 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));
264
265 /* Check for an error from flash driver. */
266 if (status)
267 {
268
269 /* Call system error handler. */
270 _lx_nand_flash_system_error(nand_flash, status, new_block, 0);
271 #ifdef LX_THREAD_SAFE_ENABLE
272
273 /* Release the thread safe mutex. */
274 tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
275 #endif
276
277 /* Return an error. */
278 return(LX_ERROR);
279 }
280 }
281
282 /* Check new block status to see if there is valid pages in the block. */
283 if ((new_block_status & LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK) == 0)
284 {
285
286 /* Add the block to free block list. */
287 _lx_nand_flash_free_block_list_add(nand_flash, new_block);
288
289 /* Set new block to unmapped. */
290 new_block = LX_NAND_BLOCK_UNMAPPED;
291 }
292 else
293 {
294
295 /* Set new block status. */
296 status = _lx_nand_flash_block_status_set(nand_flash, new_block, new_block_status);
297
298 /* Check for an error from flash driver. */
299 if (status)
300 {
301
302 /* Call system error handler. */
303 _lx_nand_flash_system_error(nand_flash, status, block, 0);
304 #ifdef LX_THREAD_SAFE_ENABLE
305
306 /* Release the thread safe mutex. */
307 tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
308 #endif
309
310 /* Return an error. */
311 return(LX_ERROR);
312 }
313 }
314
315 /* Update block mapping. */
316 _lx_nand_flash_block_mapping_set(nand_flash, logical_sector, new_block);
317
318 /* Erase old block. */
319 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);
320
321 /* Check for an error from flash driver. */
322 if (status)
323 {
324
325 /* Call system error handler. */
326 _lx_nand_flash_system_error(nand_flash, status, block, 0);
327 #ifdef LX_THREAD_SAFE_ENABLE
328
329 /* Release the thread safe mutex. */
330 tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
331 #endif
332
333 /* Return an error. */
334 return(LX_ERROR);
335 }
336
337 /* Update erase count for the old block. */
338 status = _lx_nand_flash_erase_count_set(nand_flash, block, (UCHAR)(nand_flash -> lx_nand_flash_erase_count_table[block] + 1));
339
340 /* Check for an error from flash driver. */
341 if (status)
342 {
343
344 /* Call system error handler. */
345 _lx_nand_flash_system_error(nand_flash, status, block, 0);
346 #ifdef LX_THREAD_SAFE_ENABLE
347
348 /* Release the thread safe mutex. */
349 tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
350 #endif
351
352 /* Return an error. */
353 return(LX_ERROR);
354 }
355
356 /* Check if the block has too many erases. */
357 if (nand_flash -> lx_nand_flash_erase_count_table[block] > LX_NAND_FLASH_MAX_ERASE_COUNT_DELTA)
358 {
359
360 /* Move data from less worn block. */
361 _lx_nand_flash_block_data_move(nand_flash, block);
362 }
363 else
364 {
365
366 /* Set the block status to free. */
367 status = _lx_nand_flash_block_status_set(nand_flash, block, LX_NAND_BLOCK_STATUS_FREE);
368
369 /* Check for an error from flash driver. */
370 if (status)
371 {
372
373 /* Call system error handler. */
374 _lx_nand_flash_system_error(nand_flash, status, block, 0);
375 #ifdef LX_THREAD_SAFE_ENABLE
376
377 /* Release the thread safe mutex. */
378 tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
379 #endif
380
381 /* Return an error. */
382 return(LX_ERROR);
383 }
384
385 /* Add the block to free block list. */
386 _lx_nand_flash_free_block_list_add(nand_flash, block);
387 }
388
389 /* Check if there is valid pages in the new block. */
390 if ((new_block_status & LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK) != 0)
391 {
392
393 /* Add the new block to mapped block list. */
394 _lx_nand_flash_mapped_block_list_add(nand_flash, logical_sector / nand_flash -> lx_nand_flash_pages_per_block);
395 }
396 }
397 else
398 {
399
400 /* Set page buffer to all 0xFF bytes. */
401 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);
402
403 /* Setup spare buffer pointer. */
404 spare_buffer_ptr = nand_flash -> lx_nand_flash_page_buffer + nand_flash -> lx_nand_flash_bytes_per_page;
405
406 /* Check if there is enough spare data for metadata block number. */
407 if (nand_flash -> lx_nand_flash_spare_data2_length >= sizeof(USHORT))
408 {
409
410 /* Save metadata block number in spare bytes. */
411 LX_UTILITY_SHORT_SET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data2_offset], nand_flash -> lx_nand_flash_metadata_block_number);
412 }
413
414 /* Set page type and sector address. */
415 LX_UTILITY_LONG_SET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset], LX_NAND_PAGE_TYPE_USER_DATA_RELEASED | logical_sector);
416
417 /* Write the page. */
418 #ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
419 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);
420 #else
421 status = (nand_flash -> lx_nand_flash_driver_pages_write)(block, available_pages, (UCHAR*)nand_flash -> lx_nand_flash_page_buffer, spare_buffer_ptr, 1);
422 #endif
423
424 /* Check for an error from flash driver. */
425 if (status)
426 {
427
428 /* Call system error handler. */
429 _lx_nand_flash_system_error(nand_flash, status, block, 0);
430 #ifdef LX_THREAD_SAFE_ENABLE
431
432 /* Release the thread safe mutex. */
433 tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
434 #endif
435
436 /* Return an error. */
437 return(LX_ERROR);
438 }
439
440 /* Increase available pages count. */
441 available_pages++;
442
443 /* Check if available pages count reaches total pages per block. */
444 if (available_pages == nand_flash -> lx_nand_flash_pages_per_block)
445 {
446
447 /* Set block full status flag. */
448 block_status |= LX_NAND_BLOCK_STATUS_FULL;
449 }
450
451 /* Build block status word. */
452 block_status = (USHORT)(available_pages | (block_status & ~LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK));
453
454 /* Set non sequential status flag. */
455 block_status |= LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL;
456
457 /* Set block status. */
458 status = _lx_nand_flash_block_status_set(nand_flash, block, block_status);
459
460 /* Check for an error from flash driver. */
461 if (status)
462 {
463
464 /* Call system error handler. */
465 _lx_nand_flash_system_error(nand_flash, status, block, 0);
466 #ifdef LX_THREAD_SAFE_ENABLE
467
468 /* Release the thread safe mutex. */
469 tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
470 #endif
471
472 /* Return an error. */
473 return(LX_ERROR);
474 }
475 }
476 }
477 }
478 #ifdef LX_THREAD_SAFE_ENABLE
479
480 /* Release the thread safe mutex. */
481 tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
482 #endif
483
484 /* Return status. */
485 return(status);
486 }
487
488