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