GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lx_nor_flash_sector_write.c Lines: 44 58 75.9 %
Date: 2024-03-11 05:20:25 Branches: 15 24 62.5 %

Line Branch Exec Source
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_sector_write                          PORTABLE C      */
42
/*                                                           6.3.0        */
43
/*  AUTHOR                                                                */
44
/*                                                                        */
45
/*    William E. Lamie, Microsoft Corporation                             */
46
/*                                                                        */
47
/*  DESCRIPTION                                                           */
48
/*                                                                        */
49
/*    This function writes a logical sector to the NOR flash.             */
50
/*                                                                        */
51
/*  INPUT                                                                 */
52
/*                                                                        */
53
/*    nor_flash                             NOR flash instance            */
54
/*    logical_sector                        Logical sector number         */
55
/*    buffer                                Pointer to buffer to write    */
56
/*                                            (the size is 512 bytes)     */
57
/*                                                                        */
58
/*  OUTPUT                                                                */
59
/*                                                                        */
60
/*    return status                                                       */
61
/*                                                                        */
62
/*  CALLS                                                                 */
63
/*                                                                        */
64
/*    _lx_nor_flash_driver_write            Driver flash sector write     */
65
/*    _lx_nor_flash_driver_read             Driver flash sector read      */
66
/*    _lx_nor_flash_block_reclaim           Reclaim one flash block       */
67
/*    _lx_nor_flash_logical_sector_find     Find logical sector           */
68
/*    _lx_nor_flash_physical_sector_allocate                              */
69
/*                                          Allocate new physical sector  */
70
/*    _lx_nor_flash_sector_mapping_cache_invalidate                       */
71
/*                                          Invalidate cache entry        */
72
/*    _lx_nor_flash_system_error            Internal system error handler */
73
/*    tx_mutex_get                          Get thread protection         */
74
/*    tx_mutex_put                          Release thread protection     */
75
/*                                                                        */
76
/*  CALLED BY                                                             */
77
/*                                                                        */
78
/*    Application Code                                                    */
79
/*                                                                        */
80
/*  RELEASE HISTORY                                                       */
81
/*                                                                        */
82
/*    DATE              NAME                      DESCRIPTION             */
83
/*                                                                        */
84
/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
85
/*  09-30-2020     William E. Lamie         Modified comment(s),          */
86
/*                                            resulting in version 6.1    */
87
/*  06-02-2021     Bhupendra Naphade        Modified comment(s),          */
88
/*                                            resulting in version 6.1.7  */
89
/*  10-31-2023     Xiuwen Cai               Modified comment(s),          */
90
/*                                            added mapping bitmap cache, */
91
/*                                            added obsolete count cache, */
92
/*                                            resulting in version 6.3.0  */
93
/*                                                                        */
94
/**************************************************************************/
95
2756
UINT  _lx_nor_flash_sector_write(LX_NOR_FLASH *nor_flash, ULONG logical_sector, VOID *buffer)
96
{
97
98
ULONG                           *old_mapping_address;
99
ULONG                           *old_sector_address;
100
ULONG                           old_mapping_entry;
101
ULONG                           *new_mapping_address;
102
ULONG                           *new_sector_address;
103
ULONG                           new_mapping_entry;
104
ULONG                           i;
105
LX_NOR_SECTOR_MAPPING_CACHE_ENTRY  *sector_mapping_cache_entry_ptr;
106
UINT                            status;
107
#ifdef LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE
108
ULONG                           block;
109
#endif
110
111
#ifdef LX_THREAD_SAFE_ENABLE
112
113
    /* Obtain the thread safe mutex.  */
114
    tx_mutex_get(&nor_flash -> lx_nor_flash_mutex, TX_WAIT_FOREVER);
115
#endif
116
117
    /* Determine if there are less than two block's worth of free sectors.  */
118
2756
    i =  0;
119
3896
    while (nor_flash -> lx_nor_flash_free_physical_sectors <= nor_flash -> lx_nor_flash_physical_sectors_per_block)
120
    {
121
122
        /* Attempt to reclaim one physical block.  */
123
1140
        _lx_nor_flash_block_reclaim(nor_flash);
124
125
        /* Increment the block count.  */
126
1140
        i++;
127
128
        /* Have we exceeded the number of blocks in the system?  */
129
1140
        if (i >= nor_flash -> lx_nor_flash_total_blocks)
130
        {
131
132
            /* Yes, break out of the loop.  */
133
            break;
134
        }
135
    }
136
137
    /* Increment the number of write requests.  */
138
2756
    nor_flash -> lx_nor_flash_write_requests++;
139
140
    /* See if we can find the sector in the current mapping.  */
141
2756
    _lx_nor_flash_logical_sector_find(nor_flash, logical_sector, LX_FALSE, &old_mapping_address, &old_sector_address);
142
143
    /* Allocate a new physical sector for this write.  */
144
2756
    _lx_nor_flash_physical_sector_allocate(nor_flash, logical_sector, &new_mapping_address, &new_sector_address);
145
146
    /* Determine if the new sector allocation was successful.  */
147
2756
    if (new_mapping_address)
148
    {
149
150
        /* Yes, we were able to allocate a new physical sector.  */
151
152
        /* Update the number of free physical sectors.  */
153
2756
        nor_flash -> lx_nor_flash_free_physical_sectors--;
154
155
        /* Write the sector data to the new physical sector.  */
156
2756
        status =  _lx_nor_flash_driver_write(nor_flash, new_sector_address, buffer, LX_NOR_SECTOR_SIZE);
157
158
        /* Check for an error from flash driver. Drivers should never return an error..  */
159
2756
        if (status)
160
        {
161
162
            /* Call system error handler.  */
163
            _lx_nor_flash_system_error(nor_flash, status);
164
165
#ifdef LX_THREAD_SAFE_ENABLE
166
167
            /* Release the thread safe mutex.  */
168
            tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
169
#endif
170
171
            /* Return status.  */
172
            return(LX_ERROR);
173
        }
174
175
        /* Was there a previously mapped sector?  */
176
2756
        if (old_mapping_address)
177
        {
178
179
            /* Now deprecate the old sector mapping.  */
180
181
            /* Read in the old sector mapping.  */
182
#ifdef LX_DIRECT_READ
183
184
            /* Read the word directly.  */
185
            old_mapping_entry =  *(old_mapping_address);
186
#else
187
2238
            status =  _lx_nor_flash_driver_read(nor_flash, old_mapping_address, &old_mapping_entry, 1);
188
189
            /* Check for an error from flash driver. Drivers should never return an error..  */
190
2238
            if (status)
191
            {
192
193
                /* Call system error handler.  */
194
                _lx_nor_flash_system_error(nor_flash, status);
195
196
#ifdef LX_THREAD_SAFE_ENABLE
197
198
                /* Release the thread safe mutex.  */
199
                tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
200
#endif
201
202
                /* Return status.  */
203
                return(LX_ERROR);
204
            }
205
#endif
206
207
            /* Clear bit 30, which indicates this sector is superceded.  */
208
2238
            old_mapping_entry =  old_mapping_entry & ~((ULONG) LX_NOR_PHYSICAL_SECTOR_SUPERCEDED);
209
210
            /* Write the value back to the flash to clear bit 30.  */
211
2238
            status =  _lx_nor_flash_driver_write(nor_flash, old_mapping_address, &old_mapping_entry, 1);
212
213
            /* Check for an error from flash driver. Drivers should never return an error..  */
214
2238
            if (status)
215
            {
216
217
                /* Call system error handler.  */
218
                _lx_nor_flash_system_error(nor_flash, status);
219
220
#ifdef LX_THREAD_SAFE_ENABLE
221
222
                /* Release the thread safe mutex.  */
223
                tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
224
#endif
225
226
                /* Return status.  */
227
                return(LX_ERROR);
228
            }
229
        }
230
231
        /* Now build the new mapping entry - with the not valid bit set initially.  */
232
2756
        new_mapping_entry =  ((ULONG) LX_NOR_PHYSICAL_SECTOR_VALID) | ((ULONG) LX_NOR_PHYSICAL_SECTOR_SUPERCEDED) | ((ULONG) LX_NOR_PHYSICAL_SECTOR_MAPPING_NOT_VALID) | logical_sector;
233
234
        /* Write out the new mapping entry.  */
235
2756
        status =  _lx_nor_flash_driver_write(nor_flash, new_mapping_address, &new_mapping_entry, 1);
236
237
        /* Check for an error from flash driver. Drivers should never return an error..  */
238
2756
        if (status)
239
        {
240
241
            /* Call system error handler.  */
242
            _lx_nor_flash_system_error(nor_flash, status);
243
244
#ifdef LX_THREAD_SAFE_ENABLE
245
246
            /* Release the thread safe mutex.  */
247
            tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
248
#endif
249
250
            /* Return status.  */
251
            return(LX_ERROR);
252
        }
253
254
        /* Now clear the not valid bit to make this sector mapping valid.  This is done because the writing of the extra bytes itself can
255
           be interrupted and we need to make sure this can be detected when the flash is opened again.  */
256
2756
        new_mapping_entry =  new_mapping_entry & ~((ULONG) LX_NOR_PHYSICAL_SECTOR_MAPPING_NOT_VALID);
257
258
        /* Clear the not valid bit.  */
259
2756
        status =  _lx_nor_flash_driver_write(nor_flash, new_mapping_address, &new_mapping_entry, 1);
260
261
        /* Check for an error from flash driver. Drivers should never return an error..  */
262
2756
        if (status)
263
        {
264
265
            /* Call system error handler.  */
266
            _lx_nor_flash_system_error(nor_flash, status);
267
268
#ifdef LX_THREAD_SAFE_ENABLE
269
270
            /* Release the thread safe mutex.  */
271
            tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
272
#endif
273
274
            /* Return status.  */
275
            return(LX_ERROR);
276
        }
277
#ifndef LX_NOR_DISABLE_EXTENDED_CACHE
278
#ifdef LX_NOR_ENABLE_MAPPING_BITMAP
279
280
        /* Determine if the logical sector is within the mapping bitmap.  */
281
        if (logical_sector < nor_flash -> lx_nor_flash_extended_cache_mapping_bitmap_max_logical_sector)
282
        {
283
284
            /* Set the bit in the mapping bitmap.  */
285
            nor_flash -> lx_nor_flash_extended_cache_mapping_bitmap[logical_sector >> 5] |= (ULONG)(1 << (logical_sector & 31));
286
        }
287
#endif
288
#endif
289
290
        /* Increment the number of mapped physical sectors.  */
291
2756
        nor_flash -> lx_nor_flash_mapped_physical_sectors++;
292
293
        /* Was there a previously mapped sector?  */
294
2756
        if (old_mapping_address)
295
        {
296
297
            /* Now clear bit 31, which indicates this sector is now obsoleted.  */
298
2238
            old_mapping_entry =  old_mapping_entry & ~((ULONG) LX_NOR_PHYSICAL_SECTOR_VALID);
299
300
            /* Write the value back to the flash to clear bit 31.  */
301
2238
            status =  _lx_nor_flash_driver_write(nor_flash, old_mapping_address, &old_mapping_entry, 1);
302
303
            /* Check for an error from flash driver. Drivers should never return an error..  */
304
2238
            if (status)
305
            {
306
307
                /* Call system error handler.  */
308
                _lx_nor_flash_system_error(nor_flash, status);
309
310
#ifdef LX_THREAD_SAFE_ENABLE
311
312
                /* Release the thread safe mutex.  */
313
                tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
314
#endif
315
316
              /* Return status.  */
317
                return(LX_ERROR);
318
            }
319
320
            /* Increment the number of obsolete physical sectors.  */
321
2238
            nor_flash -> lx_nor_flash_obsolete_physical_sectors++;
322
323
#ifdef LX_NOR_ENABLE_OBSOLETE_COUNT_CACHE
324
325
            /* Get the block number from mapping address.  */
326
            block = (ULONG)(old_mapping_address - nor_flash -> lx_nor_flash_base_address) / nor_flash -> lx_nor_flash_words_per_block;
327
328
            /* Determine if this block is within the range of the obsolete count cache.  */
329
            if (block < nor_flash -> lx_nor_flash_extended_cache_obsolete_count_max_block)
330
            {
331
332
                /* Increment the obsolete count for this block.  */
333
                nor_flash -> lx_nor_flash_extended_cache_obsolete_count[block] ++;
334
            }
335
#endif
336
337
            /* Decrement the number of mapped physical sectors.  */
338
2238
            nor_flash -> lx_nor_flash_mapped_physical_sectors--;
339
340
            /* Invalidate the old sector mapping cache entry.  */
341
2238
            _lx_nor_flash_sector_mapping_cache_invalidate(nor_flash, logical_sector);
342
        }
343
344
        /* Determine if the sector mapping cache is enabled.  */
345
2756
        if (nor_flash -> lx_nor_flash_sector_mapping_cache_enabled)
346
        {
347
348
            /* Yes, sector mapping cache is enabled, place this sector information in the cache.  */
349
350
            /* Calculate the starting index of the sector mapping cache for this sector entry.  */
351
2756
            i =  (logical_sector & LX_NOR_SECTOR_MAPPING_CACHE_HASH_MASK) * LX_NOR_SECTOR_MAPPING_CACHE_DEPTH;
352
353
            /* Build a pointer to the cache entry.  */
354
2756
            sector_mapping_cache_entry_ptr =  &nor_flash -> lx_nor_flash_sector_mapping_cache[i];
355
356
            /* Move all the cache entries down so the oldest is at the bottom.  */
357
2756
            *(sector_mapping_cache_entry_ptr + 3) =  *(sector_mapping_cache_entry_ptr + 2);
358
2756
            *(sector_mapping_cache_entry_ptr + 2) =  *(sector_mapping_cache_entry_ptr + 1);
359
2756
            *(sector_mapping_cache_entry_ptr + 1) =  *(sector_mapping_cache_entry_ptr);
360
361
            /* Setup the new sector information in the cache.  */
362
2756
            sector_mapping_cache_entry_ptr -> lx_nor_sector_mapping_cache_logical_sector =             (logical_sector | LX_NOR_SECTOR_MAPPING_CACHE_ENTRY_VALID);
363
2756
            sector_mapping_cache_entry_ptr -> lx_nor_sector_mapping_cache_physical_sector_map_entry =  new_mapping_address;
364
2756
            sector_mapping_cache_entry_ptr -> lx_nor_sector_mapping_cache_physical_sector_address =    new_sector_address;
365
        }
366
367
        /* Indicate the write was successful.  */
368
2756
        status =  LX_SUCCESS;
369
    }
370
    else
371
    {
372
373
        /* Indicate the write was unsuccessful.  */
374
        status =  LX_NO_SECTORS;
375
    }
376
377
#ifdef LX_THREAD_SAFE_ENABLE
378
379
    /* Release the thread safe mutex.  */
380
    tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
381
#endif
382
383
    /* Return the completion status.  */
384
2756
    return(status);
385
}
386
387