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_next_block_to_erase_find              PORTABLE C      */
43 /*                                                           6.1.7        */
44 /*  AUTHOR                                                                */
45 /*                                                                        */
46 /*    William E. Lamie, Microsoft Corporation                             */
47 /*                                                                        */
48 /*  DESCRIPTION                                                           */
49 /*                                                                        */
50 /*    This function finds the next block to erase in the NOR flash.       */
51 /*                                                                        */
52 /*  INPUT                                                                 */
53 /*                                                                        */
54 /*    nor_flash                             NOR flash instance            */
55 /*    return_erase_block                    Returned block to erase       */
56 /*    return_erase_count                    Returned erase count of block */
57 /*    return_mapped_sectors                 Returned number of mapped     */
58 /*                                            sectors                     */
59 /*    return_obsolete_sectors               Returned number of obsolete   */
60 /*                                            sectors                     */
61 /*                                                                        */
62 /*  OUTPUT                                                                */
63 /*                                                                        */
64 /*    return status                                                       */
65 /*                                                                        */
66 /*  CALLS                                                                 */
67 /*                                                                        */
68 /*    _lx_nor_flash_driver_read             Driver flash sector read      */
69 /*    _lx_nor_flash_system_error            Internal system error handler */
70 /*                                                                        */
71 /*  CALLED BY                                                             */
72 /*                                                                        */
73 /*    Internal LevelX                                                     */
74 /*                                                                        */
75 /*  RELEASE HISTORY                                                       */
76 /*                                                                        */
77 /*    DATE              NAME                      DESCRIPTION             */
78 /*                                                                        */
79 /*  05-19-2020     William E. Lamie         Initial Version 6.0           */
80 /*  09-30-2020     William E. Lamie         Modified comment(s),          */
81 /*                                            resulting in version 6.1    */
82 /*  06-02-2021     Bhupendra Naphade        Modified comment(s),          */
83 /*                                            resulting in version 6.1.7  */
84 /*                                                                        */
85 /**************************************************************************/
_lx_nor_flash_next_block_to_erase_find(LX_NOR_FLASH * nor_flash,ULONG * return_erase_block,ULONG * return_erase_count,ULONG * return_mapped_sectors,ULONG * return_obsolete_sectors)86 UINT  _lx_nor_flash_next_block_to_erase_find(LX_NOR_FLASH *nor_flash, ULONG *return_erase_block, ULONG *return_erase_count, ULONG *return_mapped_sectors, ULONG *return_obsolete_sectors)
87 {
88 
89 ULONG   *block_word_ptr;
90 ULONG   *list_word_ptr;
91 ULONG   list_word;
92 ULONG   i, j;
93 ULONG   mapped_sectors;
94 ULONG   erase_count;
95 ULONG   obsolete_sectors;
96 ULONG   min_block_erase = 0;
97 ULONG   min_block_erase_count;
98 ULONG   min_block_obsolete_count = 0;
99 ULONG   min_block_mapped_count = 0;
100 ULONG   max_obsolete_sectors;
101 ULONG   max_obsolete_block = 0;
102 ULONG   max_obsolete_erase_count = 0;
103 ULONG   max_obsolete_mapped_count = 0;
104 ULONG   min_system_block_erase_count;
105 ULONG   max_system_block_erase_count;
106 ULONG   erase_count_threshold;
107 #ifndef LX_DIRECT_READ
108 UINT    status;
109 #endif
110 
111 
112     /* Setup the block word pointer to the first word of the search block.  */
113     block_word_ptr =  nor_flash -> lx_nor_flash_base_address;
114 
115     /* Initialize the minimum erase count.  */
116     min_block_erase_count =  LX_ALL_ONES;
117 
118     /* Initialize the system minimum and maximum erase counts.  */
119     min_system_block_erase_count =  LX_ALL_ONES;
120     max_system_block_erase_count =  0;
121 
122     /* Initialize the maximum obsolete sector count.  */
123     max_obsolete_sectors =  0;
124 
125     /* Calculate the erase count threshold.  */
126     if (nor_flash -> lx_nor_flash_free_physical_sectors >= nor_flash -> lx_nor_flash_physical_sectors_per_block)
127     {
128 
129         /* Calculate erase count threshold by adding constant to the current minimum.  */
130         erase_count_threshold =  nor_flash -> lx_nor_flash_minimum_erase_count + LX_NOR_FLASH_MAX_ERASE_COUNT_DELTA;
131     }
132     else
133     {
134 
135         /* When the number of free sectors is low, simply pick the block that has the most number of obsolete sectors.  */
136         erase_count_threshold =  LX_ALL_ONES;
137     }
138 
139     /* Loop through the blocks to attempt to find the mapped logical sector.  */
140     for (i = 0; i < nor_flash -> lx_nor_flash_total_blocks; i++)
141     {
142 
143         /* Read the erase count of this block.  */
144 #ifdef LX_DIRECT_READ
145 
146         /* Read the word directly.  */
147         erase_count =  *(block_word_ptr);
148 #else
149         status =  _lx_nor_flash_driver_read(nor_flash, block_word_ptr, &erase_count, 1);
150 
151         /* Check for an error from flash driver. Drivers should never return an error..  */
152         if (status)
153         {
154 
155             /* Call system error handler.  */
156             _lx_nor_flash_system_error(nor_flash, status);
157 
158             /* Return the error.  */
159             return(status);
160         }
161 #endif
162 
163         /* Update the system minimum and maximum erase counts.  */
164         if (erase_count < min_system_block_erase_count)
165             min_system_block_erase_count =  erase_count;
166         if (erase_count > max_system_block_erase_count)
167             max_system_block_erase_count =  erase_count;
168 
169         /* Compute the number of obsolete and mapped sectors for this block.  */
170         obsolete_sectors =  0;
171         mapped_sectors =    0;
172 
173         /* Setup a pointer to the mapped list.  */
174         list_word_ptr =  block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset;
175 
176         /* Loop through the mapped list for this block.  */
177         for (j = 0; j < nor_flash -> lx_nor_flash_physical_sectors_per_block; j++)
178         {
179 
180             /* Read the current mapping entry.  */
181 #ifdef LX_DIRECT_READ
182 
183             /* Read the word directly.  */
184             list_word =  *(list_word_ptr);
185 #else
186             status =  _lx_nor_flash_driver_read(nor_flash, list_word_ptr, &list_word, 1);
187 
188             /* Check for an error from flash driver. Drivers should never return an error..  */
189             if (status)
190             {
191 
192                 /* Call system error handler.  */
193                 _lx_nor_flash_system_error(nor_flash, status);
194 
195                 /* Return the error.  */
196                 return(status);
197             }
198 #endif
199 
200             /* Determine if the entry hasn't been used.  */
201             if (list_word == LX_NOR_PHYSICAL_SECTOR_FREE)
202             {
203 
204                 /* Since allocations are done sequentially in the block, we know nothing
205                    else exists after this point.  */
206                 break;
207             }
208 
209             /* Is this entry obsolete?  */
210             if ((list_word & LX_NOR_PHYSICAL_SECTOR_VALID) == 0)
211             {
212 
213                 /* Increment the number of obsolete sectors.  */
214                 obsolete_sectors++;
215             }
216             else
217             {
218 
219                 /* Increment the number of mapped sectors.  */
220                 mapped_sectors++;
221             }
222 
223             /* Move the list pointer ahead.  */
224             list_word_ptr++;
225         }
226 
227         /* Determine if we have a block with a new maximum number of obsolete sectors.  */
228         if ((obsolete_sectors > max_obsolete_sectors) && (erase_count <= erase_count_threshold))
229         {
230 
231             /* Update the new maximum obsolete sectors and related information.  */
232             max_obsolete_sectors =      obsolete_sectors;
233             max_obsolete_block =        i;
234             max_obsolete_erase_count =  erase_count;
235             max_obsolete_mapped_count = mapped_sectors;
236         }
237         else if ((max_obsolete_sectors) && (obsolete_sectors == max_obsolete_sectors) && (erase_count <= erase_count_threshold))
238         {
239 
240             /* Another block has the same number of obsolete sectors.  Does this new block have a smaller erase
241                count?  */
242             if (erase_count < max_obsolete_erase_count)
243             {
244 
245                 /* Yes, erase the block with the smaller erase count.  */
246                 max_obsolete_sectors =      obsolete_sectors;
247                 max_obsolete_block =        i;
248                 max_obsolete_erase_count =  erase_count;
249                 max_obsolete_mapped_count = mapped_sectors;
250             }
251         }
252 
253         /* Determine if we have a new minimum erase count.  */
254         if (erase_count < min_block_erase_count)
255         {
256 
257             /* Update the new minimum erase count and related information.  */
258             min_block_erase_count =     erase_count;
259             min_block_erase =           i;
260             min_block_obsolete_count =  obsolete_sectors;
261             min_block_mapped_count =    mapped_sectors;
262         }
263 
264         /* Move to the next block.  */
265         block_word_ptr =  block_word_ptr + nor_flash -> lx_nor_flash_words_per_block;
266     }
267 
268     /* Determine if we can erase the block with the most obsolete sectors.  */
269     if (max_obsolete_sectors)
270     {
271 
272         /* Erase the block with the most obsolete sectors.  */
273         *return_erase_block =       max_obsolete_block;
274         *return_erase_count =       max_obsolete_erase_count;
275         *return_obsolete_sectors =  max_obsolete_sectors;
276         *return_mapped_sectors =    max_obsolete_mapped_count;
277     }
278     else
279     {
280 
281         /* Otherwise, choose the block with the smallest erase count.  */
282         *return_erase_block =       min_block_erase;
283         *return_erase_count =       min_block_erase_count;
284         *return_obsolete_sectors =  min_block_obsolete_count;
285         *return_mapped_sectors =    min_block_mapped_count;
286     }
287 
288     /* Update the overall minimum and maximum erase count.  */
289     nor_flash -> lx_nor_flash_minimum_erase_count =  min_system_block_erase_count;
290     nor_flash -> lx_nor_flash_maximum_erase_count =  max_system_block_erase_count;
291 
292     /* Return success.  */
293     return(LX_SUCCESS);
294 }
295 
296