GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lx_nand_flash_sector_release.c Lines: 57 83 68.7 %
Date: 2024-03-11 05:20:25 Branches: 36 56 64.3 %

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
/**   NAND 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_nand_flash_sector_release                       PORTABLE C      */
42
/*                                                           6.2.1       */
43
/*  AUTHOR                                                                */
44
/*                                                                        */
45
/*    Xiuwen Cai, Microsoft Corporation                                   */
46
/*                                                                        */
47
/*  DESCRIPTION                                                           */
48
/*                                                                        */
49
/*    This function releases a logical sector from being managed in the   */
50
/*    NAND flash.                                                         */
51
/*                                                                        */
52
/*  INPUT                                                                 */
53
/*                                                                        */
54
/*    nand_flash                            NAND flash instance           */
55
/*    logical_sector                        Logical sector number         */
56
/*                                                                        */
57
/*  OUTPUT                                                                */
58
/*                                                                        */
59
/*    return status                                                       */
60
/*                                                                        */
61
/*  CALLS                                                                 */
62
/*                                                                        */
63
/*    _lx_nand_flash_block_find             Find the mapped block         */
64
/*    lx_nand_flash_driver_pages_read       Read pages                    */
65
/*    _lx_nand_flash_block_allocate         Allocate block                */
66
/*    _lx_nand_flash_mapped_block_list_remove                             */
67
/*                                          Remove mapped block           */
68
/*    _lx_nand_flash_data_page_copy         Copy data pages               */
69
/*    _lx_nand_flash_free_block_list_add    Add free block to list        */
70
/*    _lx_nand_flash_block_mapping_set      Set block mapping             */
71
/*    _lx_nand_flash_driver_block_erase     Erase block                   */
72
/*    _lx_nand_flash_erase_count_set        Set erase count               */
73
/*    _lx_nand_flash_block_data_move        Move block data               */
74
/*    _lx_nand_flash_block_status_set       Set block status              */
75
/*    _lx_nand_flash_mapped_block_list_add  Add mapped block to list      */
76
/*    _lx_nand_flash_system_error           Internal system error handler */
77
/*    tx_mutex_get                          Get thread protection         */
78
/*    tx_mutex_put                          Release thread protection     */
79
/*                                                                        */
80
/*  CALLED BY                                                             */
81
/*                                                                        */
82
/*    Application Code                                                    */
83
/*                                                                        */
84
/*  RELEASE HISTORY                                                       */
85
/*                                                                        */
86
/*    DATE              NAME                      DESCRIPTION             */
87
/*                                                                        */
88
/*  03-08-2023     Xiuwen Cai               Initial Version 6.2.1        */
89
/*                                                                        */
90
/**************************************************************************/
91
6738
UINT  _lx_nand_flash_sector_release(LX_NAND_FLASH *nand_flash, ULONG logical_sector)
92
{
93
94
UINT        status;
95
ULONG       block;
96
USHORT      block_status;
97
UCHAR       *spare_buffer_ptr;
98
ULONG       available_pages;
99
LONG        page;
100
6738
UINT        release_sector = LX_FALSE;
101
ULONG       new_block;
102
USHORT      new_block_status;
103
104
#ifdef LX_THREAD_SAFE_ENABLE
105
106
    /* Obtain the thread safe mutex.  */
107
    tx_mutex_get(&nand_flash -> lx_nand_flash_mutex, TX_WAIT_FOREVER);
108
#endif
109
110
    /* Increment the number of release requests.  */
111
6738
    nand_flash -> lx_nand_flash_diagnostic_sector_release_requests++;
112
113
114
    /* See if we can find the sector in the current mapping.  */
115
6738
    status = _lx_nand_flash_block_find(nand_flash, logical_sector, &block, &block_status);
116
117
    /* Check return status.   */
118
6738
    if (status != LX_SUCCESS)
119
    {
120
121
        /* Call system error handler.  */
122
        _lx_nand_flash_system_error(nand_flash, status, block, 0);
123
124
        /* Determine if the error is fatal.  */
125
        if (status != LX_NAND_ERROR_CORRECTED)
126
        {
127
#ifdef LX_THREAD_SAFE_ENABLE
128
129
            /* Release the thread safe mutex.  */
130
            tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
131
#endif
132
133
            /* Return an error.  */
134
            return(LX_ERROR);
135
        }
136
    }
137
138
    /* Determine if the block is mapped.  */
139
6738
    if (block != LX_NAND_BLOCK_UNMAPPED)
140
    {
141
142
        /* Setup spare buffer pointer.  */
143
358
        spare_buffer_ptr = (UCHAR*)nand_flash -> lx_nand_flash_page_buffer;
144
145
        /* Get available pages in this block.  */
146
358
        available_pages = block_status & LX_NAND_BLOCK_STATUS_FULL ? nand_flash -> lx_nand_flash_pages_per_block : block_status & LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK;
147
148
        /* Determine if the pages are recorded sequentially.  */
149
358
        if (block_status & LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL)
150
        {
151
152
            /* Loop to search the logical page.  */
153
11769
            for (page = (LONG)available_pages - 1; page >= 0; page--)
154
            {
155
156
                /* Read a page.  */
157
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
158
                status = (nand_flash -> lx_nand_flash_driver_pages_read)(nand_flash, block, (ULONG)page, LX_NULL, spare_buffer_ptr, 1);
159
#else
160
11413
                status = (nand_flash -> lx_nand_flash_driver_pages_read)(block, (ULONG)page, LX_NULL, spare_buffer_ptr, 1);
161
#endif
162
163
                /* Check for an error from flash driver.   */
164
11413
                if (status)
165
                {
166
167
                    /* Call system error handler.  */
168
                    _lx_nand_flash_system_error(nand_flash, status, block, 0);
169
#ifdef LX_THREAD_SAFE_ENABLE
170
171
                    /* Release the thread safe mutex.  */
172
                    tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
173
#endif
174
175
                    /* Return an error.  */
176
                    return(LX_ERROR);
177
                }
178
179
                /* Get the logical sector number from spare bytes, and check if it matches the addressed sector number.  */
180
11413
                if ((LX_UTILITY_LONG_GET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset]) & LX_NAND_PAGE_TYPE_USER_DATA_MASK) == logical_sector)
181
                {
182
183
                    /* Make sure the sector is not released.  */
184
52
                    if ((LX_UTILITY_LONG_GET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset]) & (~LX_NAND_PAGE_TYPE_USER_DATA_MASK)) == (LX_NAND_PAGE_TYPE_USER_DATA))
185
                    {
186
187
                        /* Set release sector flag.  */
188
52
                        release_sector = LX_TRUE;
189
                    }
190
                }
191
            }
192
        }
193
        else
194
        {
195
196
            /* Check if the logical sector is available.  */
197
2
            if (logical_sector % nand_flash -> lx_nand_flash_pages_per_block < available_pages)
198
            {
199
200
                /* Set release sector flag.  */
201
2
                release_sector = LX_TRUE;
202
            }
203
        }
204
205
        /* Determine if the sector needs to be released.  */
206
358
        if (release_sector)
207
        {
208
209
            /* Check if the block is full.  */
210
54
            if (block_status & LX_NAND_BLOCK_STATUS_FULL)
211
            {
212
213
                /* Allocate a new block.  */
214
2
                status = _lx_nand_flash_block_allocate(nand_flash, &new_block);
215
216
                /* Check return status.   */
217
2
                if (status != LX_SUCCESS)
218
                {
219
                    /* Call system error handler.  */
220
                    _lx_nand_flash_system_error(nand_flash, status, new_block, 0);
221
#ifdef LX_THREAD_SAFE_ENABLE
222
223
                    /* Release the thread safe mutex.  */
224
                    tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
225
#endif
226
227
                    /* Return an error.  */
228
                    return(LX_ERROR);
229
230
                }
231
232
                /* Set new block status to allocated.  */
233
2
                new_block_status = LX_NAND_BLOCK_STATUS_ALLOCATED;
234
235
                /* Remove the old block from mapped block list.  */
236
2
                _lx_nand_flash_mapped_block_list_remove(nand_flash, logical_sector / nand_flash -> lx_nand_flash_pages_per_block);
237
238
                /* Copy valid sector to new block.  */
239
2
                status = _lx_nand_flash_data_page_copy(nand_flash, logical_sector - (logical_sector % nand_flash -> lx_nand_flash_pages_per_block), block, block_status, new_block, &new_block_status, (logical_sector % nand_flash -> lx_nand_flash_pages_per_block));
240
241
                /* Check for an error from flash driver.   */
242
2
                if (status)
243
                {
244
245
                    /* Call system error handler.  */
246
                    _lx_nand_flash_system_error(nand_flash, status, new_block, 0);
247
#ifdef LX_THREAD_SAFE_ENABLE
248
249
                    /* Release the thread safe mutex.  */
250
                    tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
251
#endif
252
253
                    /* Return an error.  */
254
                    return(LX_ERROR);
255
                }
256
257
                /* Determine if there are sectors after the addressed sector need to be copied.  */
258
2
                if (logical_sector % nand_flash -> lx_nand_flash_pages_per_block < nand_flash -> lx_nand_flash_pages_per_block - 1)
259
                {
260
261
                    /* Copy valid sector to new block.  */
262
2
                    status = _lx_nand_flash_data_page_copy(nand_flash, logical_sector + 1, block, block_status, new_block, &new_block_status, (nand_flash -> lx_nand_flash_pages_per_block - 1) - (logical_sector % nand_flash -> lx_nand_flash_pages_per_block));
263
264
                    /* Check for an error from flash driver.   */
265
2
                    if (status)
266
                    {
267
268
                        /* Call system error handler.  */
269
                        _lx_nand_flash_system_error(nand_flash, status, new_block, 0);
270
#ifdef LX_THREAD_SAFE_ENABLE
271
272
                        /* Release the thread safe mutex.  */
273
                        tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
274
#endif
275
276
                        /* Return an error.  */
277
                        return(LX_ERROR);
278
                    }
279
                }
280
281
                /* Check new block status to see if there is valid pages in the block.  */
282
2
                if ((new_block_status & LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK) == 0)
283
                {
284
285
                    /* Add the block to free block list.  */
286
                    _lx_nand_flash_free_block_list_add(nand_flash, new_block);
287
288
                    /* Set new block to unmapped.  */
289
                    new_block = LX_NAND_BLOCK_UNMAPPED;
290
                }
291
                else
292
                {
293
294
                    /* Set new block status.  */
295
2
                    status = _lx_nand_flash_block_status_set(nand_flash, new_block, new_block_status);
296
297
                    /* Check for an error from flash driver.   */
298
2
                    if (status)
299
                    {
300
301
                        /* Call system error handler.  */
302
                        _lx_nand_flash_system_error(nand_flash, status, block, 0);
303
#ifdef LX_THREAD_SAFE_ENABLE
304
305
                        /* Release the thread safe mutex.  */
306
                        tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
307
#endif
308
309
                        /* Return an error.  */
310
                        return(LX_ERROR);
311
                    }
312
                }
313
314
                /* Update block mapping.  */
315
2
                _lx_nand_flash_block_mapping_set(nand_flash, logical_sector, new_block);
316
317
                /* Erase old block.  */
318
2
                status = _lx_nand_flash_driver_block_erase(nand_flash, block, nand_flash -> lx_nand_flash_base_erase_count + nand_flash -> lx_nand_flash_erase_count_table[block] + 1);
319
320
                /* Check for an error from flash driver.   */
321
2
                if (status)
322
                {
323
324
                    /* Call system error handler.  */
325
                    _lx_nand_flash_system_error(nand_flash, status, block, 0);
326
#ifdef LX_THREAD_SAFE_ENABLE
327
328
                    /* Release the thread safe mutex.  */
329
                    tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
330
#endif
331
332
                    /* Return an error.  */
333
                    return(LX_ERROR);
334
                }
335
336
                /* Update erase count for the old block.  */
337
2
                status = _lx_nand_flash_erase_count_set(nand_flash, block, (UCHAR)(nand_flash -> lx_nand_flash_erase_count_table[block] + 1));
338
339
                /* Check for an error from flash driver.   */
340
2
                if (status)
341
                {
342
343
                    /* Call system error handler.  */
344
                    _lx_nand_flash_system_error(nand_flash, status, block, 0);
345
#ifdef LX_THREAD_SAFE_ENABLE
346
347
                    /* Release the thread safe mutex.  */
348
                    tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
349
#endif
350
351
                    /* Return an error.  */
352
                    return(LX_ERROR);
353
                }
354
355
                /* Check if the block has too many erases.  */
356
2
                if (nand_flash -> lx_nand_flash_erase_count_table[block] > LX_NAND_FLASH_MAX_ERASE_COUNT_DELTA)
357
                {
358
359
                    /* Move data from less worn block.  */
360
                    _lx_nand_flash_block_data_move(nand_flash, block);
361
                }
362
                else
363
                {
364
365
                    /* Set the block status to free.  */
366
2
                    status = _lx_nand_flash_block_status_set(nand_flash, block, LX_NAND_BLOCK_STATUS_FREE);
367
368
                    /* Check for an error from flash driver.   */
369
2
                    if (status)
370
                    {
371
372
                        /* Call system error handler.  */
373
                        _lx_nand_flash_system_error(nand_flash, status, block, 0);
374
#ifdef LX_THREAD_SAFE_ENABLE
375
376
                        /* Release the thread safe mutex.  */
377
                        tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
378
#endif
379
380
                        /* Return an error.  */
381
                        return(LX_ERROR);
382
                    }
383
384
                    /* Add the block to free block list.  */
385
2
                    _lx_nand_flash_free_block_list_add(nand_flash, block);
386
                }
387
388
                /* Check if there is valid pages in the new block.  */
389
2
                if ((new_block_status & LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK) != 0)
390
                {
391
392
                    /* Add the new block to mapped block list.  */
393
2
                    _lx_nand_flash_mapped_block_list_add(nand_flash, logical_sector / nand_flash -> lx_nand_flash_pages_per_block);
394
                }
395
            }
396
            else
397
            {
398
399
                /* Set page buffer to all 0xFF bytes.  */
400
27508
                LX_MEMSET(nand_flash -> lx_nand_flash_page_buffer, 0xFF, nand_flash -> lx_nand_flash_bytes_per_page + nand_flash -> lx_nand_flash_spare_total_length);
401
402
                /* Setup spare buffer pointer.  */
403
52
                spare_buffer_ptr = nand_flash -> lx_nand_flash_page_buffer + nand_flash -> lx_nand_flash_bytes_per_page;
404
405
                /* Check if there is enough spare data for metadata block number.  */
406
52
                if (nand_flash -> lx_nand_flash_spare_data2_length >= sizeof(USHORT))
407
                {
408
409
                    /* Save metadata block number in spare bytes.  */
410
52
                    LX_UTILITY_SHORT_SET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data2_offset], nand_flash -> lx_nand_flash_metadata_block_number);
411
                }
412
413
                /* Set page type and sector address.  */
414
52
                LX_UTILITY_LONG_SET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset], LX_NAND_PAGE_TYPE_USER_DATA_RELEASED | logical_sector);
415
416
                /* Write the page.  */
417
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
418
                status = (nand_flash -> lx_nand_flash_driver_pages_write)(nand_flash, block, available_pages, (UCHAR*)nand_flash -> lx_nand_flash_page_buffer, spare_buffer_ptr, 1);
419
#else
420
52
                status = (nand_flash -> lx_nand_flash_driver_pages_write)(block, available_pages, (UCHAR*)nand_flash -> lx_nand_flash_page_buffer, spare_buffer_ptr, 1);
421
#endif
422
423
                /* Check for an error from flash driver.   */
424
52
                if (status)
425
                {
426
427
                    /* Call system error handler.  */
428
                    _lx_nand_flash_system_error(nand_flash, status, block, 0);
429
#ifdef LX_THREAD_SAFE_ENABLE
430
431
                    /* Release the thread safe mutex.  */
432
                    tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
433
#endif
434
435
                    /* Return an error.  */
436
                    return(LX_ERROR);
437
                }
438
439
                /* Increase available pages count.  */
440
52
                available_pages++;
441
442
                /* Check if available pages count reaches total pages per block.  */
443
52
                if (available_pages == nand_flash -> lx_nand_flash_pages_per_block)
444
                {
445
446
                    /* Set block full status flag.  */
447
2
                    block_status |= LX_NAND_BLOCK_STATUS_FULL;
448
                }
449
450
                /* Build block status word.  */
451
52
                block_status = (USHORT)(available_pages | (block_status & ~LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK));
452
453
                /* Set non sequential status flag.  */
454
52
                block_status |= LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL;
455
456
                /* Set block status.  */
457
52
                status = _lx_nand_flash_block_status_set(nand_flash, block, block_status);
458
459
                /* Check for an error from flash driver.   */
460
52
                if (status)
461
                {
462
463
                    /* Call system error handler.  */
464
                    _lx_nand_flash_system_error(nand_flash, status, block, 0);
465
#ifdef LX_THREAD_SAFE_ENABLE
466
467
                    /* Release the thread safe mutex.  */
468
                    tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
469
#endif
470
471
                    /* Return an error.  */
472
                    return(LX_ERROR);
473
                }
474
            }
475
        }
476
    }
477
#ifdef LX_THREAD_SAFE_ENABLE
478
479
    /* Release the thread safe mutex.  */
480
    tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
481
#endif
482
483
    /* Return status.  */
484
6738
    return(status);
485
}
486