GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lx_nand_flash_sector_write.c Lines: 54 76 71.1 %
Date: 2026-03-06 18:45:40 Branches: 36 52 69.2 %

Line Branch Exec Source
1
/***************************************************************************
2
 * Copyright (c) 2024 Microsoft Corporation
3
 * Copyright (c) 2026-present Eclipse ThreadX contributors
4
 *
5
 * This program and the accompanying materials are made available under the
6
 * terms of the MIT License which is available at
7
 * https://opensource.org/licenses/MIT.
8
 *
9
 * SPDX-License-Identifier: MIT
10
 **************************************************************************/
11
12
13
/**************************************************************************/
14
/**************************************************************************/
15
/**                                                                       */
16
/** LevelX Component                                                      */
17
/**                                                                       */
18
/**   NAND 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_nand_flash_sector_write                         PORTABLE C      */
43
/*                                                           6.2.1       */
44
/*  AUTHOR                                                                */
45
/*                                                                        */
46
/*    Xiuwen Cai, Microsoft Corporation                                   */
47
/*                                                                        */
48
/*  DESCRIPTION                                                           */
49
/*                                                                        */
50
/*    This function writes a logical sector to the NAND flash page.       */
51
/*                                                                        */
52
/*  INPUT                                                                 */
53
/*                                                                        */
54
/*    nand_flash                            NAND flash instance           */
55
/*    logical_sector                        Logical sector number         */
56
/*    buffer                                Pointer to buffer to write    */
57
/*                                            (the size is number of      */
58
/*                                             bytes in a page)           */
59
/*                                                                        */
60
/*  OUTPUT                                                                */
61
/*                                                                        */
62
/*    return status                                                       */
63
/*                                                                        */
64
/*  CALLS                                                                 */
65
/*                                                                        */
66
/*    _lx_nand_flash_block_find             Find the mapped block         */
67
/*    _lx_nand_flash_block_allocate         Allocate block                */
68
/*    _lx_nand_flash_mapped_block_list_remove                             */
69
/*                                          Remove mapped block           */
70
/*    _lx_nand_flash_data_page_copy         Copy data pages               */
71
/*    _lx_nand_flash_free_block_list_add    Add free block to list        */
72
/*    _lx_nand_flash_block_mapping_set      Set block mapping             */
73
/*    lx_nand_flash_driver_pages_write      Write pages                   */
74
/*    _lx_nand_flash_block_status_set       Set block status              */
75
/*    _lx_nand_flash_driver_block_erase     Erase block                   */
76
/*    _lx_nand_flash_erase_count_set        Set erase count               */
77
/*    _lx_nand_flash_block_data_move        Move block data               */
78
/*    _lx_nand_flash_mapped_block_list_add  Add mapped block to list      */
79
/*    _lx_nand_flash_system_error           Internal system error handler */
80
/*    tx_mutex_get                          Get thread protection         */
81
/*    tx_mutex_put                          Release thread protection     */
82
/*                                                                        */
83
/*  CALLED BY                                                             */
84
/*                                                                        */
85
/*    Application Code                                                    */
86
/*                                                                        */
87
/**************************************************************************/
88
32300
UINT  _lx_nand_flash_sector_write(LX_NAND_FLASH *nand_flash, ULONG logical_sector, VOID *buffer)
89
{
90
91
UINT                                status;
92
ULONG                               block;
93
ULONG                               new_block;
94
ULONG                               page;
95
32300
USHORT                              block_status = 0;
96
32300
USHORT                              new_block_status = LX_NAND_BLOCK_STATUS_ALLOCATED;
97
UCHAR                               *spare_buffer_ptr;
98
32300
UINT                                update_mapping = LX_FALSE;
99
32300
UINT                                copy_block = LX_FALSE;
100
101
#ifdef LX_THREAD_SAFE_ENABLE
102
103
    /* Obtain the thread safe mutex.  */
104
    tx_mutex_get(&nand_flash -> lx_nand_flash_mutex, TX_WAIT_FOREVER);
105
#endif
106
107
    /* Increment the number of write requests.  */
108
32300
    nand_flash -> lx_nand_flash_diagnostic_sector_write_requests++;
109
110
    /* See if we can find the logical sector in the current mapping.  */
111
32300
    status = _lx_nand_flash_block_find(nand_flash, logical_sector, &block, &block_status);
112
113
    /* Check return status.   */
114
32300
    if(status != LX_SUCCESS)
115
    {
116
117
        /* Call system error handler.  */
118
        _lx_nand_flash_system_error(nand_flash, status, block, 0);
119
120
        /* Determine if the error is fatal.  */
121
        if (status != LX_NAND_ERROR_CORRECTED)
122
        {
123
#ifdef LX_THREAD_SAFE_ENABLE
124
125
            /* Release the thread safe mutex.  */
126
            tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
127
#endif
128
129
            /* Return an error.  */
130
            return(LX_ERROR);
131
        }
132
    }
133
134
    /* Check if block is unmapped or block is full.  */
135

32300
    if (block == LX_NAND_BLOCK_UNMAPPED || block_status & LX_NAND_BLOCK_STATUS_FULL)
136
    {
137
138
        /* Allocate a new block.  */
139
1323
        status = _lx_nand_flash_block_allocate(nand_flash, &new_block);
140
141
        /* Check if there is no blocks.  */
142
1323
        if (status == LX_NO_BLOCKS)
143
        {
144
#ifdef LX_THREAD_SAFE_ENABLE
145
146
            /* Release the thread safe mutex.  */
147
            tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
148
#endif
149
150
            /* Return error.  */
151
            return(status);
152
        }
153
154
        /* Check return status.  */
155
1323
        else if (status != LX_SUCCESS)
156
        {
157
158
            /* Call system error handler.  */
159
            _lx_nand_flash_system_error(nand_flash, status, new_block, 0);
160
161
            /* Determine if the error is fatal.  */
162
            if (status != LX_NAND_ERROR_CORRECTED)
163
            {
164
#ifdef LX_THREAD_SAFE_ENABLE
165
166
                /* Release the thread safe mutex.  */
167
                tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
168
#endif
169
170
                /* Return an error.  */
171
                return(LX_ERROR);
172
            }
173
        }
174
175
        /* Check if the block is full.  */
176
1323
        if (block_status & LX_NAND_BLOCK_STATUS_FULL)
177
        {
178
179
            /* Set copy block flag.  */
180
1140
            copy_block = LX_TRUE;
181
        }
182
183
        /* Set update mapping flag.  */
184
1323
        update_mapping = LX_TRUE;
185
    }
186
    else
187
    {
188
189
        /* Set new block to the same as old block.  */
190
30977
        new_block = block;
191
30977
        new_block_status = block_status;
192
    }
193
194
    /* Check if copy block flag is set.  */
195
32300
    if (copy_block)
196
    {
197
198
        /* Remove the old block from mapped block list.  */
199
1140
        _lx_nand_flash_mapped_block_list_remove(nand_flash, logical_sector / nand_flash -> lx_nand_flash_pages_per_block);
200
201
        /* Copy valid sector to new block.  */
202
1140
        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));
203
204
        /* Check for an error from flash driver.   */
205
1140
        if (status)
206
        {
207
208
            /* Call system error handler.  */
209
            _lx_nand_flash_system_error(nand_flash, status, block, 0);
210
#ifdef LX_THREAD_SAFE_ENABLE
211
212
            /* Release the thread safe mutex.  */
213
            tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
214
#endif
215
216
            /* Return an error.  */
217
            return(LX_ERROR);
218
        }
219
    }
220
221
    /* Check if update mapping flag is set.  */
222
32300
    if (update_mapping)
223
    {
224
225
        /* Update block mapping.  */
226
1323
        _lx_nand_flash_block_mapping_set(nand_flash, logical_sector, new_block);
227
    }
228
229
    /* Setup spare buffer pointer.  */
230
32300
    spare_buffer_ptr = nand_flash -> lx_nand_flash_page_buffer;
231
232
    /* Set spare buffer to all 0xFF bytes.  */
233
549100
    LX_MEMSET(spare_buffer_ptr, 0xFF, nand_flash -> lx_nand_flash_spare_total_length);
234
235
    /* Check if there is enough spare data for metadata block number.  */
236
32300
    if (nand_flash -> lx_nand_flash_spare_data2_length >= sizeof(USHORT))
237
    {
238
239
        /* Save metadata block number in spare bytes.  */
240
32300
        LX_UTILITY_SHORT_SET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data2_offset], nand_flash -> lx_nand_flash_metadata_block_number);
241
    }
242
243
    /* Set page type and sector address.  */
244
32300
    LX_UTILITY_LONG_SET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset], LX_NAND_PAGE_TYPE_USER_DATA | logical_sector);
245
246
    /* Get page to write.  */
247
32300
    page = new_block_status & LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK;
248
249
    /* Write the page.  */
250
#ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
251
    status = (nand_flash -> lx_nand_flash_driver_pages_write)(nand_flash, new_block, page, (UCHAR*)buffer, spare_buffer_ptr, 1);
252
#else
253
32300
    status = (nand_flash -> lx_nand_flash_driver_pages_write)(new_block, page, (UCHAR*)buffer, spare_buffer_ptr, 1);
254
#endif
255
256
    /* Check for an error from flash driver.   */
257
32300
    if (status)
258
    {
259
260
        /* Call system error handler.  */
261
        _lx_nand_flash_system_error(nand_flash, status, new_block, 0);
262
#ifdef LX_THREAD_SAFE_ENABLE
263
264
        /* Release the thread safe mutex.  */
265
        tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
266
#endif
267
268
        /* Return an error.  */
269
        return(LX_ERROR);
270
    }
271
272
    /* Determine if the sector number is sequential.  */
273
32300
    if ((new_block_status & LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK) != (logical_sector % nand_flash -> lx_nand_flash_pages_per_block))
274
    {
275
276
        /* Set non sequential status flag.  */
277
9680
        new_block_status |= LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL;
278
    }
279
280
    /* Increase page number.  */
281
32300
    page++;
282
283
    /* Check if page number reaches total pages per block.  */
284
32300
    if (page == nand_flash -> lx_nand_flash_pages_per_block)
285
    {
286
287
        /* Set block full status flag.  */
288
90
        new_block_status |= LX_NAND_BLOCK_STATUS_FULL;
289
    }
290
291
    /* Build block status word.  */
292
32300
    new_block_status = (USHORT)(page | (new_block_status & ~LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK));
293
294
    /* Determine if there are sectors after the addressed sector need to be copied.  */
295

32300
    if (copy_block && ((logical_sector % nand_flash -> lx_nand_flash_pages_per_block) < (nand_flash -> lx_nand_flash_pages_per_block - 1)))
296
    {
297
298
        /* Copy valid sector to new block.  */
299
1134
        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));
300
301
        /* Check for an error from flash driver.   */
302
1134
        if (status)
303
        {
304
305
            /* Call system error handler.  */
306
            _lx_nand_flash_system_error(nand_flash, status, block, 0);
307
#ifdef LX_THREAD_SAFE_ENABLE
308
309
            /* Release the thread safe mutex.  */
310
            tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
311
#endif
312
313
            /* Return an error.  */
314
            return(LX_ERROR);
315
        }
316
    }
317
318
    /* Set new block status.  */
319
32300
    status = _lx_nand_flash_block_status_set(nand_flash, new_block, new_block_status);
320
321
    /* Check for an error from flash driver.   */
322
32300
    if (status)
323
    {
324
325
        /* Call system error handler.  */
326
        _lx_nand_flash_system_error(nand_flash, status, new_block, 0);
327
#ifdef LX_THREAD_SAFE_ENABLE
328
329
        /* Release the thread safe mutex.  */
330
        tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
331
#endif
332
333
        /* Return an error.  */
334
        return(LX_ERROR);
335
    }
336
337
    /* Check if copy block flag is set.  */
338
32300
    if (copy_block)
339
    {
340
341
        /* Erase old block.  */
342
1140
        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);
343
344
        /* Check for an error from flash driver.   */
345
1140
        if (status)
346
        {
347
348
            /* Call system error handler.  */
349
            _lx_nand_flash_system_error(nand_flash, status, block, 0);
350
#ifdef LX_THREAD_SAFE_ENABLE
351
352
            /* Release the thread safe mutex.  */
353
            tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
354
#endif
355
356
            /* Return an error.  */
357
            return(LX_ERROR);
358
        }
359
360
        /* Update erase count for the old block.  */
361
1140
        status = _lx_nand_flash_erase_count_set(nand_flash, block, (UCHAR)(nand_flash -> lx_nand_flash_erase_count_table[block] + 1));
362
363
        /* Check for an error from flash driver.   */
364
1140
        if (status)
365
        {
366
367
            /* Call system error handler.  */
368
            _lx_nand_flash_system_error(nand_flash, status, block, 0);
369
#ifdef LX_THREAD_SAFE_ENABLE
370
371
            /* Release the thread safe mutex.  */
372
            tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
373
#endif
374
375
            /* Return an error.  */
376
            return(LX_ERROR);
377
        }
378
379
        /* Check if the block has too many erases.  */
380
1140
        if (nand_flash -> lx_nand_flash_erase_count_table[block] > LX_NAND_FLASH_MAX_ERASE_COUNT_DELTA)
381
        {
382
383
            /* Move data from less worn block.  */
384
            _lx_nand_flash_block_data_move(nand_flash, block);
385
        }
386
        else
387
        {
388
389
            /* Set the block status to free.  */
390
1140
            status = _lx_nand_flash_block_status_set(nand_flash, block, LX_NAND_BLOCK_STATUS_FREE);
391
392
            /* Check for an error from flash driver.   */
393
1140
            if (status)
394
            {
395
396
                /* Call system error handler.  */
397
                _lx_nand_flash_system_error(nand_flash, status, block, 0);
398
#ifdef LX_THREAD_SAFE_ENABLE
399
400
                /* Release the thread safe mutex.  */
401
                tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
402
#endif
403
404
                /* Return an error.  */
405
                return(LX_ERROR);
406
            }
407
408
            /* Add the block to free block list.  */
409
1140
            _lx_nand_flash_free_block_list_add(nand_flash, block);
410
        }
411
    }
412
413
    /* Check if update mapping flag is set.  */
414
32300
    if (update_mapping)
415
    {
416
417
        /* Add the new block to mapped block list.  */
418
1323
        _lx_nand_flash_mapped_block_list_add(nand_flash, logical_sector / nand_flash -> lx_nand_flash_pages_per_block);
419
    }
420
421
#ifdef LX_THREAD_SAFE_ENABLE
422
423
    /* Release the thread safe mutex.  */
424
    tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
425
#endif
426
427
    /* Return the completion status.  */
428
32300
    return(status);
429
}
430
431