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_physical_sector_allocate              PORTABLE C      */
43 /*                                                           6.1.7        */
44 /*  AUTHOR                                                                */
45 /*                                                                        */
46 /*    William E. Lamie, Microsoft Corporation                             */
47 /*                                                                        */
48 /*  DESCRIPTION                                                           */
49 /*                                                                        */
50 /*    This function allocates a free physical sector for mapping to a     */
51 /*    logical sector.                                                     */
52 /*                                                                        */
53 /*  INPUT                                                                 */
54 /*                                                                        */
55 /*    nor_flash                             NOR flash instance            */
56 /*    logical_sector                        Logical sector number         */
57 /*    physical_sector_map_entry             Pointer to sector map entry   */
58 /*    physical_sector_address               Address of physical sector    */
59 /*                                                                        */
60 /*  OUTPUT                                                                */
61 /*                                                                        */
62 /*    return status                                                       */
63 /*                                                                        */
64 /*  CALLS                                                                 */
65 /*                                                                        */
66 /*    _lx_nor_flash_driver_write            Driver flash sector write     */
67 /*    _lx_nor_flash_driver_read             Driver flash sector read      */
68 /*    _lx_nor_flash_system_error            Internal system error handler */
69 /*                                                                        */
70 /*  CALLED BY                                                             */
71 /*                                                                        */
72 /*    Internal LevelX                                                     */
73 /*                                                                        */
74 /*  RELEASE HISTORY                                                       */
75 /*                                                                        */
76 /*    DATE              NAME                      DESCRIPTION             */
77 /*                                                                        */
78 /*  05-19-2020     William E. Lamie         Initial Version 6.0           */
79 /*  09-30-2020     William E. Lamie         Modified comment(s),          */
80 /*                                            resulting in version 6.1    */
81 /*  06-02-2021     Bhupendra Naphade        Modified comment(s),          */
82 /*                                            resulting in version 6.1.7  */
83 /*                                                                        */
84 /**************************************************************************/
_lx_nor_flash_physical_sector_allocate(LX_NOR_FLASH * nor_flash,ULONG logical_sector,ULONG ** physical_sector_map_entry,ULONG ** physical_sector_address)85 UINT  _lx_nor_flash_physical_sector_allocate(LX_NOR_FLASH *nor_flash, ULONG logical_sector, ULONG **physical_sector_map_entry, ULONG **physical_sector_address)
86 {
87 
88 ULONG   search_block;
89 ULONG   *block_word_ptr;
90 ULONG   block_word;
91 ULONG   min_logical_sector;
92 ULONG   max_logical_sector;
93 ULONG   *list_word_ptr;
94 ULONG   list_word;
95 ULONG   i, j, k, l;
96 UINT    status;
97 
98 
99     /* Increment the number of physical sector allocation requests.  */
100     nor_flash -> lx_nor_flash_physical_block_allocates++;
101 
102     /* Initialize the return parameters.  */
103     *physical_sector_map_entry =  (ULONG *) 0;
104     *physical_sector_address =    (ULONG *) 0;
105 
106     /* Determine if there are any free physical sectors.  */
107     if (nor_flash -> lx_nor_flash_free_physical_sectors == 0)
108     {
109 
110         /* Increment the number of failed allocations.  */
111         nor_flash -> lx_nor_flash_physical_block_allocate_errors++;
112 
113         /* No free physical sectors, return .  */
114         return(LX_NO_SECTORS);
115     }
116 
117     /* Pickup the search for a free physical sector at the specified block.  */
118     search_block =  nor_flash -> lx_nor_flash_free_block_search;
119 
120     /* Loop through the blocks to find a free physical sector.  */
121     for (i = 0; i < nor_flash -> lx_nor_flash_total_blocks; i++)
122     {
123 
124         /* Setup the block word pointer to the first word of the search block.  */
125         block_word_ptr =  nor_flash -> lx_nor_flash_base_address + (search_block * nor_flash -> lx_nor_flash_words_per_block);
126 
127         /* Find the first free physical sector from the free sector bit map of this block.  */
128         for (j = 0; j < nor_flash -> lx_nor_flash_block_bit_map_words; j++)
129         {
130 
131             /* Read this word of the free sector bit map.  */
132 #ifdef LX_DIRECT_READ
133 
134             /* Read the word directly.  */
135             block_word =  *(block_word_ptr + nor_flash -> lx_nor_flash_block_free_bit_map_offset + j);
136 #else
137             status =  _lx_nor_flash_driver_read(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_free_bit_map_offset + j), &block_word, 1);
138 
139             /* Check for an error from flash driver. Drivers should never return an error..  */
140             if (status)
141             {
142 
143                 /* Call system error handler.  */
144                 _lx_nor_flash_system_error(nor_flash, status);
145 
146                 /* Return the error.  */
147                 return(status);
148             }
149 #endif
150 
151             /* Are there any free sectors in this word?  */
152             if (block_word)
153             {
154 
155                 /* Yes, there are free sectors in this word.  */
156                 for (k = 0; k < 32; k++)
157                 {
158 
159                     /* Is this sector free?  */
160                     if (block_word & 1)
161                     {
162 
163                         /* Yes, this sector is free, clear the bit for this sector in the free sector map.  */
164 
165                         /* Read this word of the free sector bit map again.  */
166 #ifdef LX_DIRECT_READ
167 
168                         /* Read the word directly.  */
169                         block_word =  *(block_word_ptr + nor_flash -> lx_nor_flash_block_free_bit_map_offset + j);
170 #else
171                         status =  _lx_nor_flash_driver_read(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_free_bit_map_offset + j), &block_word, 1);
172 
173                         /* Check for an error from flash driver. Drivers should never return an error..  */
174                         if (status)
175                         {
176 
177                             /* Call system error handler.  */
178                             _lx_nor_flash_system_error(nor_flash, status);
179 
180                             /* Return the error.  */
181                             return(status);
182                         }
183 #endif
184 
185                         /* Clear the bit associated with the free sector to indicate it is not free.  */
186                         block_word =  block_word & ~(((ULONG) 1) << k);
187 
188                         /* Now write back free bit map word with the bit for this sector cleared.  */
189                         status =  _lx_nor_flash_driver_write(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_free_bit_map_offset + j), &block_word, 1);
190 
191                         /* Check for an error from flash driver. Drivers should never return an error..  */
192                         if (status)
193                         {
194 
195                             /* Call system error handler.  */
196                             _lx_nor_flash_system_error(nor_flash, status);
197 
198                             /* Return the error.  */
199                             return(status);
200                         }
201 
202                         /* Determine if this is the last entry available in this block.  */
203                         if (((block_word >> 1) == 0) && (j == (nor_flash -> lx_nor_flash_block_bit_map_words - 1)))
204                         {
205 
206                             /* This is the last physical sector in the block.  Now we need to calculate the minimum valid logical
207                                sector and the maximum valid logical sector.  */
208 
209                             /* Setup the minimum and maximum logical sectors to the current logical sector.  */
210                             min_logical_sector =  logical_sector;
211                             max_logical_sector =  logical_sector;
212 
213                             /* Setup a pointer to the mapped list.  */
214                             list_word_ptr =  block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset;
215 
216                             /* Loop to search the mapped list.  */
217                             for (l = 0; l < nor_flash -> lx_nor_flash_physical_sectors_per_block; l++)
218                             {
219 
220                                 /* Read the mapped sector entry.  */
221 #ifdef LX_DIRECT_READ
222 
223                                 /* Read the word directly.  */
224                                 list_word =  *(list_word_ptr);
225 #else
226                                 status =  _lx_nor_flash_driver_read(nor_flash, list_word_ptr, &list_word, 1);
227 
228                                 /* Check for an error from flash driver. Drivers should never return an error..  */
229                                 if (status)
230                                 {
231 
232                                     /* Call system error handler.  */
233                                     _lx_nor_flash_system_error(nor_flash, status);
234 
235                                     /* Return the error.  */
236                                     return(status);
237                                 }
238 #endif
239 
240                                 /* Is this entry valid?  */
241                                 if (list_word & LX_NOR_PHYSICAL_SECTOR_VALID)
242                                 {
243 
244                                     /* Isolate the logical sector.  */
245                                     list_word =  list_word & LX_NOR_LOGICAL_SECTOR_MASK;
246 
247                                     /* Determine if a new minimum has been found.  */
248                                     if (list_word < min_logical_sector)
249                                         min_logical_sector =  list_word;
250 
251                                     /* Determine if a new maximum has been found.  */
252                                     if (list_word != LX_NOR_LOGICAL_SECTOR_MASK)
253                                     {
254                                         if (list_word > max_logical_sector)
255                                             max_logical_sector =  list_word;
256                                     }
257                                 }
258 
259                                 /* Move the list pointer ahead.  */
260                                 list_word_ptr++;
261                             }
262 
263                             /* Move the search pointer forward, since we know this block is exhausted.  */
264                             search_block++;
265 
266                             /* Check for wrap condition on the search block.  */
267                             if (search_block >= nor_flash -> lx_nor_flash_total_blocks)
268                             {
269 
270                                 /* Reset search block to the beginning.  */
271                                 search_block =  0;
272                             }
273 
274                             /* Now write the minimum and maximum logical sector in this block.  */
275                             status =  _lx_nor_flash_driver_write(nor_flash, block_word_ptr + LX_NOR_FLASH_MIN_LOGICAL_SECTOR_OFFSET, &min_logical_sector, 1);
276 
277                             /* Check for an error from flash driver. Drivers should never return an error..  */
278                             if (status)
279                             {
280 
281                                 /* Call system error handler.  */
282                                 _lx_nor_flash_system_error(nor_flash, status);
283 
284                                 /* Return the error.  */
285                                 return(status);
286                             }
287 
288                             status =  _lx_nor_flash_driver_write(nor_flash, block_word_ptr + LX_NOR_FLASH_MAX_LOGICAL_SECTOR_OFFSET, &max_logical_sector, 1);
289 
290                             /* Check for an error from flash driver. Drivers should never return an error..  */
291                             if (status)
292                             {
293 
294                                 /* Call system error handler.  */
295                                 _lx_nor_flash_system_error(nor_flash, status);
296 
297                                 /* Return the error.  */
298                                 return(status);
299                             }
300                         }
301 
302                         /* Remember the block to search.  */
303                         nor_flash -> lx_nor_flash_free_block_search =  search_block;
304 
305                         /* Prepare the return information.  */
306                         *physical_sector_map_entry =  block_word_ptr + (nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + (j * 32)) + k;
307                         *physical_sector_address =    block_word_ptr + (nor_flash -> lx_nor_flash_block_physical_sector_offset) + (((j * 32) + k) * LX_NOR_SECTOR_SIZE);
308 
309                         /* Return success!  */
310                         return(LX_SUCCESS);
311                     }
312 
313                     /* Shift down the bit map.  */
314                     block_word =  block_word >> 1;
315 
316                     /* Determine if there are any more bits set? If not, we can break out of the search of this word.  */
317                     if (block_word == 0)
318                         break;
319                 }
320             }
321         }
322 
323         /* Move to the next flash block.  */
324         search_block++;
325 
326         /* Determine if we have to wrap the search block.  */
327         if (search_block >= nor_flash -> lx_nor_flash_total_blocks)
328         {
329 
330             /* Set the search block to the beginning.  */
331             search_block =  0;
332         }
333     }
334 
335     /* Increment the number of failed allocations.  */
336     nor_flash -> lx_nor_flash_physical_block_allocate_errors++;
337 
338     /* Return no sector completion.  */
339     return(LX_NO_SECTORS);
340 }
341 
342