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_extended_cache_enable                 PORTABLE C      */
42 /*                                                           6.3.0        */
43 /*  AUTHOR                                                                */
44 /*                                                                        */
45 /*    William E. Lamie, Microsoft Corporation                             */
46 /*                                                                        */
47 /*  DESCRIPTION                                                           */
48 /*                                                                        */
49 /*    This function enables or disables the extended cache.               */
50 /*                                                                        */
51 /*  INPUT                                                                 */
52 /*                                                                        */
53 /*    nor_flash                             NOR flash instance            */
54 /*    memory                                Address of RAM for cache      */
55 /*    size                                  Size of the RAM for cache     */
56 /*                                                                        */
57 /*  OUTPUT                                                                */
58 /*                                                                        */
59 /*    return status                                                       */
60 /*                                                                        */
61 /*  CALLS                                                                 */
62 /*                                                                        */
63 /*    None                                                                */
64 /*                                                                        */
65 /*  CALLED BY                                                             */
66 /*                                                                        */
67 /*    Application Code                                                    */
68 /*                                                                        */
69 /*  RELEASE HISTORY                                                       */
70 /*                                                                        */
71 /*    DATE              NAME                      DESCRIPTION             */
72 /*                                                                        */
73 /*  05-19-2020     William E. Lamie         Initial Version 6.0           */
74 /*  09-30-2020     William E. Lamie         Modified comment(s),          */
75 /*                                            resulting in version 6.1    */
76 /*  12-31-2020     William E. Lamie         Modified comment(s),          */
77 /*                                            fixed compiler warnings,    */
78 /*                                            resulting in version 6.1.3  */
79 /*  06-02-2021     Bhupendra Naphade        Modified comment(s), and      */
80 /*                                            updated product constants   */
81 /*                                            resulting in version 6.1.7  */
82 /*  10-15-2021     Bhupendra Naphade        Modified comment(s), and      */
83 /*                                            added check for out of      */
84 /*                                            bound memory access,        */
85 /*                                            resulting in version 6.1.9  */
86 /*  10-31-2023     Xiuwen Cai               Modified comment(s),          */
87 /*                                            added mapping bitmap cache, */
88 /*                                            added obsolete count cache, */
89 /*                                            resulting in version 6.3.0  */
90 /*                                                                        */
91 /**************************************************************************/
_lx_nor_flash_extended_cache_enable(LX_NOR_FLASH * nor_flash,VOID * memory,ULONG size)92 UINT  _lx_nor_flash_extended_cache_enable(LX_NOR_FLASH *nor_flash, VOID *memory, ULONG size)
93 {
94 #ifndef LX_NOR_DISABLE_EXTENDED_CACHE
95 
96 UINT    i;
97 ULONG   cache_size;
98 ULONG   *cache_memory;
99 #ifdef LX_NOR_ENABLE_MAPPING_BITMAP
100 ULONG   mapping_bitmap_words;
101 ULONG   mapping_bitmap_word;
102 ULONG   logical_sector;
103 ULONG   *mapping_bitmap_ptr;
104 #endif
105 #ifdef LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE
106 ULONG   obsolete_count_words;
107 ULONG   obsolete_sectors;
108 #endif
109 #if defined(LX_NOR_ENABLE_MAPPING_BITMAP) || defined(LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE)
110 ULONG   *block_word_ptr;
111 UINT    j;
112 UINT    status;
113 ULONG   block_word;
114 #endif
115 
116 
117     /* Determine if memory was specified but with an invalid size (less than one NOR sector).  */
118     if ((memory) && (size < LX_NOR_SECTOR_SIZE))
119     {
120 
121         /* Error in memory size supplied.  */
122         return(LX_ERROR);
123     }
124 
125 #ifdef LX_THREAD_SAFE_ENABLE
126 
127     /* Obtain the thread safe mutex.  */
128     tx_mutex_get(&nor_flash -> lx_nor_flash_mutex, TX_WAIT_FOREVER);
129 #endif
130 
131     /* Initialize the internal NOR cache.  */
132     nor_flash -> lx_nor_flash_extended_cache_entries =  0;
133 
134     /* Calculate cache size in words.  */
135     cache_size = size/sizeof(ULONG);
136 
137     /* Setup cache memory pointer.  */
138     cache_memory =  (ULONG *) memory;
139 
140 #if defined(LX_NOR_ENABLE_MAPPING_BITMAP) || defined(LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE)
141 
142     /* Check if the NOR flash is opened.  */
143     if (nor_flash -> lx_nor_flash_state == LX_NOR_FLASH_OPENED)
144     {
145 #if defined(LX_NOR_ENABLE_MAPPING_BITMAP)
146 
147         /* Get the mapping bitmap cache size.  */
148         mapping_bitmap_words = (nor_flash -> lx_nor_flash_total_physical_sectors + 31) / 32;
149 
150         /* Check if the mapping bitmap cache fits in the suppiled cache memory.  */
151         if (cache_size < mapping_bitmap_words)
152         {
153 
154             /* Update the cache size.  */
155             mapping_bitmap_words = cache_size;
156         }
157 
158         /* Setup the mapping bitmap cache.  */
159         nor_flash -> lx_nor_flash_extended_cache_mapping_bitmap =  cache_memory;
160 
161         /* Setup the mapping bitmap cache size.  */
162         nor_flash -> lx_nor_flash_extended_cache_mapping_bitmap_max_logical_sector =  mapping_bitmap_words * 32;
163 
164         /* Clear the mapping bitmap cache.  */
165         for (i = 0; i < mapping_bitmap_words; i++)
166         {
167             cache_memory[i] =  0;
168         }
169 
170         /* Update the cache memory pointer.  */
171         mapping_bitmap_ptr =  cache_memory;
172 
173         /* Update the cache size.  */
174         cache_size =  cache_size - mapping_bitmap_words;
175 
176         /* Update the cache memory pointer.  */
177         cache_memory =  cache_memory + mapping_bitmap_words;
178 #endif
179 
180 #if defined(LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE)
181 
182         /* Get the obsolete count cache size.  */
183         obsolete_count_words = nor_flash -> lx_nor_flash_total_blocks * sizeof(LX_NOR_OBSOLETE_COUNT_CACHE_TYPE) / 4;
184 
185         /* Check if the obsolete count cache fits in the suppiled cache memory.  */
186         if (cache_size < obsolete_count_words)
187         {
188 
189             /* Update the cache size.  */
190             obsolete_count_words = cache_size;
191         }
192 
193         /* Setup the obsolete count cache.  */
194         nor_flash -> lx_nor_flash_extended_cache_obsolete_count =  (LX_NOR_OBSOLETE_COUNT_CACHE_TYPE*)cache_memory;
195 
196         /* Setup the obsolete count cache size.  */
197         nor_flash -> lx_nor_flash_extended_cache_obsolete_count_max_block =  obsolete_count_words * 4 / sizeof(LX_NOR_OBSOLETE_COUNT_CACHE_TYPE);
198 
199         /* Update the cache size.  */
200         cache_size =  cache_size - obsolete_count_words;
201 
202         /* Update the cache memory pointer.  */
203         cache_memory =  cache_memory + obsolete_count_words;
204 #endif
205 
206         /* Loop through the blocks.  */
207         for (i = 0; i < nor_flash -> lx_nor_flash_total_blocks; i++)
208         {
209             /* Setup the block word pointer to the first word of the block.  */
210             block_word_ptr =  (nor_flash -> lx_nor_flash_base_address + (i * nor_flash -> lx_nor_flash_words_per_block));
211 
212 #if defined(LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE)
213 
214             /* Initialize the obsolete count cache.  */
215             obsolete_sectors = 0;
216 #endif
217 
218             /* Now walk the list of logical-physical sector mapping.  */
219             for (j = 0; j < nor_flash ->lx_nor_flash_physical_sectors_per_block; j++)
220             {
221 
222                 /* Read this word of the sector mapping list.  */
223 #ifdef LX_DIRECT_READ
224 
225                 /* Read the word directly.  */
226                 block_word =  *(block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + j);
227 #else
228                 status =  _lx_nor_flash_driver_read(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + j), &block_word, 1);
229 
230                 /* Check for an error from flash driver. Drivers should never return an error..  */
231                 if (status)
232                 {
233 
234                     /* Call system error handler.  */
235                     _lx_nor_flash_system_error(nor_flash, status);
236 
237                     /* Return an error.  */
238                     return(LX_ERROR);
239                 }
240 #endif
241                 /* Determine if the entry hasn't been used.  */
242                 if (block_word == LX_NOR_PHYSICAL_SECTOR_FREE)
243                 {
244                     break;
245                 }
246 
247                 /* Is this entry valid?  */
248                 if ((block_word & (LX_NOR_PHYSICAL_SECTOR_VALID | LX_NOR_PHYSICAL_SECTOR_MAPPING_NOT_VALID)) == LX_NOR_PHYSICAL_SECTOR_VALID)
249                 {
250 #if defined(LX_NOR_ENABLE_MAPPING_BITMAP)
251 
252                     /* Yes, get the logical sector.  */
253                     logical_sector = block_word & LX_NOR_LOGICAL_SECTOR_MASK;
254 
255                     /* Get the mapping bitmap word.  */
256                     mapping_bitmap_word = logical_sector >> 5;
257 
258                     /* Check if the mapping bitmap word is within the cache.  */
259                     if (mapping_bitmap_word < mapping_bitmap_words)
260                     {
261 
262                         /* Set the bit in the mapping bitmap.  */
263                         mapping_bitmap_ptr[mapping_bitmap_word] |=  (ULONG)(1 << (logical_sector & 31));
264                     }
265 #endif
266 
267                 }
268                 else
269                 {
270 #if defined(LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE)
271 
272                     /* Increment the obsolete sector count.  */
273                     obsolete_sectors++;
274 #endif
275                 }
276             }
277 #if defined(LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE)
278 
279             /* Check if the block is cached by obsolete count cache.  */
280             if (i < nor_flash -> lx_nor_flash_extended_cache_obsolete_count_max_block)
281             {
282 
283                 /* Yes, cache the obsolete sector count.  */
284                 nor_flash -> lx_nor_flash_extended_cache_obsolete_count[i] = (LX_NOR_OBSOLETE_COUNT_CACHE_TYPE)obsolete_sectors;
285             }
286 #endif
287         }
288     }
289 #endif
290 
291     /* Loop through the memory supplied and assign to cache entries.  */
292     i =  0;
293     while (cache_size >= LX_NOR_SECTOR_SIZE)
294     {
295 
296         /* Setup this cache entry.  */
297         nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_sector_address =  LX_NULL;
298         nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_sector_memory =   cache_memory;
299         nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_access_count =    0;
300 
301         /* Move the cache memory forward.   */
302         cache_memory =  cache_memory + LX_NOR_SECTOR_SIZE;
303 
304         /* Decrement the size.  */
305         cache_size =  cache_size - LX_NOR_SECTOR_SIZE;
306 
307         /* Move to next cache entry.  */
308         i++;
309     }
310 
311     /* Save the number of cache entries.  */
312     if(i > LX_NOR_EXTENDED_CACHE_SIZE)
313     {
314 
315         nor_flash -> lx_nor_flash_extended_cache_entries =  LX_NOR_EXTENDED_CACHE_SIZE;
316     }
317     else
318     {
319 
320         nor_flash -> lx_nor_flash_extended_cache_entries =  i;
321     }
322 
323 #ifdef LX_THREAD_SAFE_ENABLE
324 
325     /* Release the thread safe mutex.  */
326     tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
327 #endif
328 
329     /* Return successful completion.  */
330     return(LX_SUCCESS);
331 #else
332 
333     LX_PARAMETER_NOT_USED(nor_flash);
334     LX_PARAMETER_NOT_USED(memory);
335     LX_PARAMETER_NOT_USED(size);
336 
337     /* Return disabled error message.  */
338     return(LX_DISABLED);
339 #endif
340 }
341 
342 
343