PageRenderTime 189ms CodeModel.GetById 43ms app.highlight 48ms RepoModel.GetById 59ms app.codeStats 1ms

/drivers/block/sun3i_nand/src/logic/merge.c

https://bitbucket.org/ndreys/linux-sunxi
C | 492 lines | 341 code | 57 blank | 94 comment | 96 complexity | b4a6007c137ce97bdbdfdd48c50b021e MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
  1/*
  2 * drivers/block/sun3i_nand/src/logic/merge.c
  3 *
  4 * (C) Copyright 2007-2012
  5 * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
  6 *
  7 * This program is free software; you can redistribute it and/or
  8 * modify it under the terms of the GNU General Public License as
  9 * published by the Free Software Foundation; either version 2 of
 10 * the License, or (at your option) any later version.
 11 *
 12 * This program is distributed in the hope that it will be useful,
 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
 15 * GNU General Public License for more details.
 16 *
 17 * You should have received a copy of the GNU General Public License
 18 * along with this program; if not, write to the Free Software
 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 20 * MA 02111-1307 USA
 21 */
 22
 23#include "../include/nand_logic.h"
 24
 25extern struct __NandDriverGlobal_t     NandDriverInfo;
 26
 27__s32 _copy_page0(__u32 SrcBlk,__u16 SrcDataPage,__u32 DstBlk,__u8 SeqPlus)
 28{
 29    __u8 seq;
 30    __u16 LogicInfo;
 31    struct __NandUserData_t UserData[2];
 32    struct __PhysicOpPara_t SrcParam,DstParam;
 33
 34    SrcParam.MDataPtr = DstParam.MDataPtr = LML_TEMP_BUF;
 35    SrcParam.SDataPtr = DstParam.SDataPtr = (void *)&UserData;
 36    MEMSET((void *)&UserData,0xff,sizeof(struct __NandUserData_t) * 2);
 37
 38    /*get seq and logicinfo*/
 39    SrcParam.SectBitmap = 0x3;
 40    LML_CalculatePhyOpPar(&SrcParam,CUR_MAP_ZONE, SrcBlk, 0);
 41    if (LML_VirtualPageRead(&SrcParam) < 0){
 42        LOGICCTL_ERR("_copy_page0 : read user data err\n");
 43        return NAND_OP_FALSE;
 44    }
 45    seq = UserData[0].PageStatus;
 46    LogicInfo = UserData[0].LogicInfo;
 47
 48    /*copy main data */
 49    SrcParam.SectBitmap = DstParam.SectBitmap = FULL_BITMAP_OF_SUPER_PAGE;
 50    LML_CalculatePhyOpPar(&SrcParam, CUR_MAP_ZONE, SrcBlk, SrcDataPage);
 51    LML_CalculatePhyOpPar(&DstParam, CUR_MAP_ZONE, DstBlk, 0);
 52
 53    if (LML_VirtualPageRead(&SrcParam) < 0){
 54        LOGICCTL_ERR("_copy_page0 : read main data err\n");
 55        return NAND_OP_FALSE;
 56    }
 57
 58    UserData[0].LogicInfo = LogicInfo;
 59    UserData[0].PageStatus = seq + SeqPlus;
 60    if (NAND_OP_TRUE != LML_VirtualPageWrite(&DstParam)){
 61        LOGICCTL_ERR("_copy_page0 : write err\n");
 62        return NAND_OP_FALSE;
 63    }
 64
 65    return NAND_OP_TRUE;
 66}
 67
 68/*!
 69*
 70* \par  Description:
 71*       This function copy valuable data from datablk to logblk,then change datablk to freeblk ,change logblk to datablk.
 72*
 73* \param  [in]       LogNum,serial number within log block space
 74* \return      sucess or failed.
 75* \note         this function was called when log block is in order,that is to say physical
 76*             page number is same with logical page number.
 77**/
 78__s32  _log2data_swap_merge(__u32 nlogical)
 79{
 80    __u16 LastUsedPage,SuperPage;
 81    struct __SuperPhyBlkType_t DataBlk;
 82    struct __LogBlkType_t LogBlk;
 83    struct __PhysicOpPara_t SrcParam,DstParam;
 84
 85    /* init info of data block and log block*/
 86    BMM_GetDataBlk(nlogical, &DataBlk);
 87    BMM_GetLogBlk(nlogical, &LogBlk);
 88    LastUsedPage = LogBlk.LastUsedPage;
 89
 90    /*copy data from data block to log block*/
 91    for (SuperPage = LastUsedPage + 1; SuperPage < PAGE_CNT_OF_SUPER_BLK; SuperPage++){
 92        /*set source and destinate address*/
 93        LML_CalculatePhyOpPar(&SrcParam,CUR_MAP_ZONE, DataBlk.PhyBlkNum, SuperPage);
 94        LML_CalculatePhyOpPar(&DstParam,CUR_MAP_ZONE, LogBlk.PhyBlk.PhyBlkNum, SuperPage);
 95        if (NAND_OP_TRUE != PHY_PageCopyback(&SrcParam,&DstParam)){
 96            LOGICCTL_ERR("swap merge : copy back err\n");
 97            return NAND_OP_FALSE;
 98        }
 99        if (NAND_OP_TRUE !=  PHY_SynchBank(DstParam.BankNum, SYNC_BANK_MODE)){
100            struct __SuperPhyBlkType_t SubBlk;
101            if (NAND_OP_TRUE != LML_BadBlkManage(&LogBlk.PhyBlk,CUR_MAP_ZONE,SuperPage,&SubBlk)){
102                LOGICCTL_ERR("swap merge : bad block manage err after copy back\n");
103                return NAND_OP_FALSE;
104            }
105            LogBlk.PhyBlk = SubBlk;
106            SuperPage -= 1;
107        }
108    }
109
110    /*move log block to data block*/
111    BMM_SetDataBlk(nlogical, &LogBlk.PhyBlk);
112    /*clear log block item*/
113    MEMSET(&LogBlk, 0xff, sizeof(struct __LogBlkType_t));
114    BMM_SetLogBlk(nlogical, &LogBlk);
115
116    /*erase data block*/
117    if ( NAND_OP_TRUE != LML_VirtualBlkErase(CUR_MAP_ZONE, DataBlk.PhyBlkNum)){
118        if (NAND_OP_TRUE != LML_BadBlkManage(&DataBlk,CUR_MAP_ZONE,0,NULL)){
119            LOGICCTL_ERR("swap merge : bad block manage err erase data block\n");
120            return NAND_OP_FALSE;
121        }
122    }
123    /*move erased data block to free block*/
124    if (DataBlk.BlkEraseCnt < 0xffff)
125        DataBlk.BlkEraseCnt ++;
126    BMM_SetFreeBlk(&DataBlk);
127
128    /*clear page map table*/
129    PMM_ClearCurMapTbl();
130
131    return  NAND_OP_TRUE;
132}
133
134/*!
135*
136* \par  Description:
137*       This function move valuable data from log block to free block,then replace them.
138*
139* \param  [in]       LogNum,serial number within log block space
140* \return      sucess or failed.
141* \note         this function was called when log block is full, and valid pages is less than half of one block.
142**/
143__s32  _free2log_move_merge(__u32 nlogical)
144{
145    __u8 bank;
146    __u16 LastUsedPage,SuperPage;
147    __u16 SrcPage,DstPage;
148    struct __SuperPhyBlkType_t FreeBlk;
149    struct __LogBlkType_t LogBlk;
150    struct __PhysicOpPara_t SrcParam,DstParam;
151
152#if (!CFG_SUPPORT_ALIGN_NAND_BNK)
153	struct __NandUserData_t UserData[2];
154#endif
155
156    /*init info of log block , and get one free block */
157    BMM_GetLogBlk(nlogical, &LogBlk);
158    if (NAND_OP_TRUE != BMM_GetFreeBlk(LOWEST_EC_TYPE, &FreeBlk))
159        return NAND_OP_FALSE;
160
161    SrcParam.MDataPtr = DstParam.MDataPtr = NULL;
162    SrcParam.SDataPtr = DstParam.SDataPtr = NULL;
163    SrcParam.SectBitmap = DstParam.SectBitmap = FULL_BITMAP_OF_SUPER_PAGE;
164
165#if (CFG_SUPPORT_ALIGN_NAND_BNK)
166
167    redo:
168    /*copy data bank by bank, for copy-back using*/
169    LastUsedPage = 0;
170    for (bank = 0; bank < INTERLEAVE_BANK_CNT; bank++)
171    {
172        DstPage = bank;
173        for (SuperPage  = bank; SuperPage < PAGE_CNT_OF_SUPER_BLK; SuperPage+= INTERLEAVE_BANK_CNT)
174        {
175            SrcPage = PMM_GetCurMapPage(SuperPage);
176            if (SrcPage != 0xffff)
177            {
178            	  /*set source and destinate address*/
179		 		LML_CalculatePhyOpPar(&SrcParam,CUR_MAP_ZONE, LogBlk.PhyBlk.PhyBlkNum, SrcPage);
180               	LML_CalculatePhyOpPar(&DstParam,CUR_MAP_ZONE, FreeBlk.PhyBlkNum, DstPage);
181                if (DstPage == 0)
182                {
183                    if ( NAND_OP_FALSE == _copy_page0(LogBlk.PhyBlk.PhyBlkNum,SrcPage,FreeBlk.PhyBlkNum,0))
184                    {
185                        LOGICCTL_ERR("move merge : copy page 0 err1\n");
186                        return NAND_OP_FALSE;
187                    }
188                }
189                else
190                {
191                    if (NAND_OP_TRUE != PHY_PageCopyback(&SrcParam,&DstParam))
192                    {
193                        LOGICCTL_ERR("move merge : copy back err\n");
194                        return NAND_OP_FALSE;
195                    }
196                }
197
198                if (NAND_OP_TRUE !=  PHY_SynchBank(DstParam.BankNum, SYNC_BANK_MODE))
199                {
200                    struct __SuperPhyBlkType_t SubBlk;
201                    if (NAND_OP_TRUE != LML_BadBlkManage(&FreeBlk,CUR_MAP_ZONE,0,&SubBlk))
202                    {
203                        LOGICCTL_ERR("move merge : bad block manage err after copy back\n");
204                        return NAND_OP_FALSE;
205                    }
206                    FreeBlk = SubBlk;
207                    goto redo;
208                }
209
210                PMM_SetCurMapPage(SuperPage,DstPage);
211                DstPage += INTERLEAVE_BANK_CNT;
212            }
213        }
214
215        /*if bank 0 is empty, need write mange info in page 0*/
216        if ((bank == 0) && (DstPage == 0))
217        {
218            if ( NAND_OP_FALSE == _copy_page0(LogBlk.PhyBlk.PhyBlkNum,0,FreeBlk.PhyBlkNum,0))
219            {
220                LOGICCTL_ERR("move merge : copy page 0 err2\n");
221                return NAND_OP_FALSE;
222            }
223			LML_CalculatePhyOpPar(&DstParam, CUR_MAP_ZONE, FreeBlk.PhyBlkNum, 0);
224            if (NAND_OP_TRUE !=  PHY_SynchBank(DstParam.BankNum, SYNC_BANK_MODE))
225            {
226                struct __SuperPhyBlkType_t SubBlk;
227                if (NAND_OP_TRUE != LML_BadBlkManage(&FreeBlk,CUR_MAP_ZONE,0,&SubBlk))
228                {
229                    LOGICCTL_ERR("move merge : bad block manage err after copy back\n");
230                    return NAND_OP_FALSE;
231                }
232                FreeBlk = SubBlk;
233                goto redo;
234            }
235        }
236
237        /*reset LastUsedPage*/
238        if ((DstPage - INTERLEAVE_BANK_CNT) > LastUsedPage)
239        {
240            LastUsedPage = DstPage - INTERLEAVE_BANK_CNT;
241        }
242    }
243
244#else
245	/*copy data page by page*/
246	DstPage = 0;
247	for (SuperPage = 0; SuperPage < PAGE_CNT_OF_LOGIC_BLK; SuperPage++)
248	{
249		SrcPage = PMM_GetCurMapPage(SuperPage);
250		if (SrcPage != 0xffff)
251		{
252			/*set source and destinate address*/
253		 	LML_CalculatePhyOpPar(&SrcParam,CUR_MAP_ZONE, LogBlk.PhyBlk.PhyBlkNum, SrcPage);
254            LML_CalculatePhyOpPar(&DstParam,CUR_MAP_ZONE, FreeBlk.PhyBlkNum, DstPage);
255			if (0 == DstPage)
256			{
257				if ( NAND_OP_FALSE == _copy_page0(LogBlk.PhyBlk.PhyBlkNum,SrcPage,FreeBlk.PhyBlkNum,0))
258                {
259                     LOGICCTL_ERR("move merge : copy page 0 err1\n");
260                     return NAND_OP_FALSE;
261                }
262			}
263			else
264			{
265				SrcParam.MDataPtr = DstParam.MDataPtr = LML_TEMP_BUF;
266				SrcParam.SDataPtr = DstParam.SDataPtr = (void *)&UserData;
267    			MEMSET((void *)&UserData,0xff,sizeof(struct __NandUserData_t) * 2);
268				SrcParam.SectBitmap = DstParam.SectBitmap = FULL_BITMAP_OF_SUPER_PAGE;
269				if (LML_VirtualPageRead(&SrcParam) < 0){
270       				 LOGICCTL_ERR("move merge : read main data err\n");
271        			 return NAND_OP_FALSE;
272    			}
273
274   				if (NAND_OP_TRUE != LML_VirtualPageWrite(&DstParam)){
275        			LOGICCTL_ERR("move merge : write err\n");
276        			return NAND_OP_FALSE;
277    			}
278			}
279			if (NAND_OP_TRUE !=  PHY_SynchBank(DstParam.BankNum, SYNC_BANK_MODE))
280            {
281            	struct __SuperPhyBlkType_t SubBlk;
282                if (NAND_OP_TRUE != LML_BadBlkManage(&FreeBlk,CUR_MAP_ZONE,LastUsedPage,&SubBlk))
283                {
284                    LOGICCTL_ERR("move merge : bad block manage err after copy back\n");
285                	return NAND_OP_FALSE;
286				}
287				FreeBlk = SubBlk;
288				SuperPage -= 1;
289			}
290			PMM_SetCurMapPage(SuperPage,DstPage);
291			LastUsedPage = DstPage;
292			DstPage++;
293		}
294	}
295
296#endif
297
298    /*erase log block*/
299    if(NAND_OP_TRUE != LML_VirtualBlkErase(CUR_MAP_ZONE, LogBlk.PhyBlk.PhyBlkNum))
300    {
301        if(NAND_OP_TRUE != LML_BadBlkManage(&LogBlk.PhyBlk,CUR_MAP_ZONE,0,NULL))
302        {
303            LOGICCTL_ERR("move merge : bad block manage err after erase log block\n");
304            return NAND_OP_FALSE;
305        }
306    }
307    /*move erased log block to free block*/
308    if(LogBlk.PhyBlk.BlkEraseCnt < 0xffff)
309    {
310        LogBlk.PhyBlk.BlkEraseCnt ++;
311    }
312    BMM_SetFreeBlk(&LogBlk.PhyBlk);
313
314    /*move free block to log block*/
315    LogBlk.PhyBlk = FreeBlk;
316    LogBlk.LastUsedPage = LastUsedPage;
317    BMM_SetLogBlk(nlogical, &LogBlk);
318
319    return NAND_OP_TRUE;
320}
321
322/*!
323*
324* \par  Description:
325*       This function copy valuable data from log block or dat block to free block, change free to data ,change
326*       data and log to free.
327*
328* \param  [in]       LogNum,serial number within log block space
329* \return      sucess or failed.
330* \note         this function was called when log block is not suit for swap or move.
331**/
332__s32  _free2data_simple_merge(__u32 nlogical)
333{
334    __u8 InData;
335    __u16 SuperPage;
336    __u16 SrcPage,DstPage;
337    __u32 SrcBlk,DstBlk;
338    struct __SuperPhyBlkType_t DataBlk;
339    struct __SuperPhyBlkType_t FreeBlk;
340    struct __LogBlkType_t LogBlk;
341    struct __PhysicOpPara_t SrcParam,DstParam;
342
343    /*init block info*/
344    BMM_GetDataBlk(nlogical,&DataBlk);
345    if (NAND_OP_TRUE != BMM_GetFreeBlk(LOWEST_EC_TYPE, &FreeBlk))
346        return NAND_OP_FALSE;
347    BMM_GetLogBlk(nlogical,&LogBlk);
348
349    /*copy data from data block or log block to free block*/
350    for (SuperPage = 0; SuperPage < PAGE_CNT_OF_LOGIC_BLK; SuperPage++)
351    {
352        /*set source address and destination address*/
353        DstPage = SuperPage;
354        DstBlk = FreeBlk.PhyBlkNum;
355        SrcPage = PMM_GetCurMapPage(SuperPage);
356        InData = (SrcPage == 0xffff)?1 : 0;
357        SrcBlk = InData?DataBlk.PhyBlkNum : LogBlk.PhyBlk.PhyBlkNum;
358        SrcPage = InData?SuperPage:SrcPage;
359		LML_CalculatePhyOpPar(&SrcParam, CUR_MAP_ZONE,SrcBlk, SrcPage);
360		LML_CalculatePhyOpPar(&DstParam, CUR_MAP_ZONE,DstBlk, DstPage);
361
362        if (DstPage == 0)
363        {
364            __u8 SeqPlus;
365            //SeqPlus = InData?1:0;
366            SeqPlus = InData?2:1;
367            if(NAND_OP_FALSE == _copy_page0(SrcBlk, SrcPage, DstBlk,SeqPlus))
368            {
369                LOGICCTL_ERR("simple_merge : copy page 0 err\n");
370                return NAND_OP_FALSE;
371            }
372        }
373        else
374        {
375            if(NAND_OP_TRUE != PHY_PageCopyback(&SrcParam,&DstParam))
376            {
377                LOGICCTL_ERR("simple merge : copy back err\n");
378                return NAND_OP_FALSE;
379            }
380        }
381
382        if(NAND_OP_TRUE != PHY_SynchBank(DstParam.BankNum, SYNC_BANK_MODE))
383        {
384            struct __SuperPhyBlkType_t SubBlk;
385            if(NAND_OP_TRUE != LML_BadBlkManage(&FreeBlk,CUR_MAP_ZONE,DstPage, &SubBlk))
386            {
387                LOGICCTL_ERR("simgple merge : bad block manage err after copy back\n");
388                return NAND_OP_FALSE;
389            }
390            FreeBlk = SubBlk;
391            SuperPage -= 1;
392        }
393    }
394
395    /*move free block to data block*/
396    BMM_SetDataBlk(nlogical, &FreeBlk);
397
398
399	/*move erased data block to free block*/
400    if ( NAND_OP_TRUE != LML_VirtualBlkErase(CUR_MAP_ZONE, DataBlk.PhyBlkNum)){
401        if (NAND_OP_TRUE != LML_BadBlkManage(&DataBlk,CUR_MAP_ZONE,0,NULL)){
402            LOGICCTL_ERR("swap merge : bad block manage err erase data block\n");
403            return NAND_OP_FALSE;
404        }
405    }
406    /*move erased data block to free block*/
407    if (DataBlk.BlkEraseCnt < 0xffff)
408        DataBlk.BlkEraseCnt ++;
409    BMM_SetFreeBlk(&DataBlk);
410
411
412    /*move erased log block to free block*/
413    if ( NAND_OP_TRUE != LML_VirtualBlkErase(CUR_MAP_ZONE, LogBlk.PhyBlk.PhyBlkNum)){
414        if (NAND_OP_TRUE != LML_BadBlkManage(&LogBlk.PhyBlk,CUR_MAP_ZONE,0,NULL)){
415            LOGICCTL_ERR("move merge : bad block manage err after erase log block\n");
416            return NAND_OP_FALSE;
417        }
418    }
419    if (LogBlk.PhyBlk.BlkEraseCnt < 0xffff)
420        LogBlk.PhyBlk.BlkEraseCnt ++;
421    BMM_SetFreeBlk(&LogBlk.PhyBlk);
422    MEMSET(&LogBlk, 0xff, sizeof(struct __LogBlkType_t));
423    BMM_SetLogBlk(nlogical, &LogBlk);
424
425
426
427    /*clear page map table*/
428    PMM_ClearCurMapTbl();
429
430    return NAND_OP_TRUE;
431
432}
433
434void _get_page_map_tbl_info(__u32 nlogical,__u8 *InOrder, __u16 *nValidPage)
435{
436    __u16 LastUsedPage,PhysicPage;
437    __u32 i;
438    struct __LogBlkType_t  LogBlk;
439
440    *InOrder = 1;
441    *nValidPage = 0;
442    BMM_GetLogBlk(nlogical, &LogBlk);
443    LastUsedPage = LogBlk.LastUsedPage;
444
445    for (i = 0; i < PAGE_CNT_OF_SUPER_BLK; i++)
446    {
447        PhysicPage = PMM_GetCurMapPage(i);
448        if (PhysicPage != 0xffff){
449            *nValidPage = *nValidPage + 1;
450            if (PhysicPage != i)
451                *InOrder = 0;
452        }
453    }
454
455    if (*nValidPage < LastUsedPage + 1)
456        *InOrder = 0;
457}
458
459/*
460************************************************************************************************************************
461*                       NAND FLASH LOGIC MANAGE LAYER MERGE LOG BLOCK
462*
463*Description: Merge the log block whoes mapping table is active.
464*
465*Arguments  : nMode     the type of the merge;
466*                       = 0     normal merge, the log block  table is not full;
467*                       = 1     special merge, the log block table is full.
468*
469*Return     : merge result;
470*               = 0     merge log successful;
471*               = -1    do bad block manage failed.
472************************************************************************************************************************
473*/
474__s32 LML_MergeLogBlk(__u32 nMode, __u32 nlogical)
475{
476    __u8 InOrder;
477    __u16 nValidPage;
478
479    _get_page_map_tbl_info(nlogical,&InOrder,&nValidPage);
480
481    if (InOrder)
482        return (_log2data_swap_merge(nlogical));
483    else{
484        if ( (nMode == SPECIAL_MERGE_MODE) && (nValidPage < PAGE_CNT_OF_SUPER_BLK/(INTERLEAVE_BANK_CNT+1)))
485            return (_free2log_move_merge(nlogical));
486        else
487            return (_free2data_simple_merge(nlogical));
488    }
489
490}
491
492