GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lx_nand_flash_sector_write.c Lines: 54 76 71.1 %
Date: 2024-03-11 05:20:25 Branches: 36 52 69.2 %

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_write                         PORTABLE C      */
42
/*                                                           6.2.1       */
43
/*  AUTHOR                                                                */
44
/*                                                                        */
45
/*    Xiuwen Cai, Microsoft Corporation                                   */
46
/*                                                                        */
47
/*  DESCRIPTION                                                           */
48
/*                                                                        */
49
/*    This function writes a logical sector to the NAND flash page.       */
50
/*                                                                        */
51
/*  INPUT                                                                 */
52
/*                                                                        */
53
/*    nand_flash                            NAND flash instance           */
54
/*    logical_sector                        Logical sector number         */
55
/*    buffer                                Pointer to buffer to write    */
56
/*                                            (the size is number of      */
57
/*                                             bytes in a page)           */
58
/*                                                                        */
59
/*  OUTPUT                                                                */
60
/*                                                                        */
61
/*    return status                                                       */
62
/*                                                                        */
63
/*  CALLS                                                                 */
64
/*                                                                        */
65
/*    _lx_nand_flash_block_find             Find the mapped block         */
66
/*    _lx_nand_flash_block_allocate         Allocate block                */
67
/*    _lx_nand_flash_mapped_block_list_remove                             */
68
/*                                          Remove mapped block           */
69
/*    _lx_nand_flash_data_page_copy         Copy data pages               */
70
/*    _lx_nand_flash_free_block_list_add    Add free block to list        */
71
/*    _lx_nand_flash_block_mapping_set      Set block mapping             */
72
/*    lx_nand_flash_driver_pages_write      Write pages                   */
73
/*    _lx_nand_flash_block_status_set       Set block status              */
74
/*    _lx_nand_flash_driver_block_erase     Erase block                   */
75
/*    _lx_nand_flash_erase_count_set        Set erase count               */
76
/*    _lx_nand_flash_block_data_move        Move block data               */
77
/*    _lx_nand_flash_mapped_block_list_add  Add mapped block to list      */
78
/*    _lx_nand_flash_system_error           Internal system error handler */
79
/*    tx_mutex_get                          Get thread protection         */
80
/*    tx_mutex_put                          Release thread protection     */
81
/*                                                                        */
82
/*  CALLED BY                                                             */
83
/*                                                                        */
84
/*    Application Code                                                    */
85
/*                                                                        */
86
/*  RELEASE HISTORY                                                       */
87
/*                                                                        */
88
/*    DATE              NAME                      DESCRIPTION             */
89
/*                                                                        */
90
/*  03-08-2023     Xiuwen Cai               Initial Version 6.2.1        */
91
/*                                                                        */
92
/**************************************************************************/
93
32300
UINT  _lx_nand_flash_sector_write(LX_NAND_FLASH *nand_flash, ULONG logical_sector, VOID *buffer)
94
{
95
96
UINT                                status;
97
ULONG                               block;
98
ULONG                               new_block;
99
ULONG                               page;
100
32300
USHORT                              block_status = 0;
101
32300
USHORT                              new_block_status = LX_NAND_BLOCK_STATUS_ALLOCATED;
102
UCHAR                               *spare_buffer_ptr;
103
32300
UINT                                update_mapping = LX_FALSE;
104
32300
UINT                                copy_block = LX_FALSE;
105
106
#ifdef LX_THREAD_SAFE_ENABLE
107
108
    /* Obtain the thread safe mutex.  */
109
    tx_mutex_get(&nand_flash -> lx_nand_flash_mutex, TX_WAIT_FOREVER);
110
#endif
111
112
    /* Increment the number of write requests.  */
113
32300
    nand_flash -> lx_nand_flash_diagnostic_sector_write_requests++;
114
115
    /* See if we can find the logical sector in the current mapping.  */
116
32300
    status = _lx_nand_flash_block_find(nand_flash, logical_sector, &block, &block_status);
117
118
    /* Check return status.   */
119
32300
    if(status != LX_SUCCESS)
120
    {
121
122
        /* Call system error handler.  */
123
        _lx_nand_flash_system_error(nand_flash, status, block, 0);
124
125
        /* Determine if the error is fatal.  */
126
        if (status != LX_NAND_ERROR_CORRECTED)
127
        {
128
#ifdef LX_THREAD_SAFE_ENABLE
129
130
            /* Release the thread safe mutex.  */
131
            tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
132
#endif
133
134
            /* Return an error.  */
135
            return(LX_ERROR);
136
        }
137
    }
138
139
    /* Check if block is unmapped or block is full.  */
140

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

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