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