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