コード例 #1
0
ファイル: bad_manage.c プロジェクト: djytw/bootloader
/*
************************************************************************************************************************
*                       RESTORE VALID PAGE DATA FROM BAD BLOCK
*
*Description: Restore the valid page data from the bad block.
*
*Arguments  : pBadBlk   the pointer to the bad physical block parameter;
*             nErrPage  the number of the error page;
*             pNewBlk   the pointer to the new valid block parameter.
*
*Return     : restore page data result;
*               = 0     restore data successful;
*               = -1    restore data failed.
************************************************************************************************************************
*/
static __s32 _RestorePageData(struct __SuperPhyBlkType_t *pBadBlk, __u32 nZoneNum, __u32 nErrPage, struct __SuperPhyBlkType_t *pNewBlk)
{
    __s32 i, result;
    struct __PhysicOpPara_t tmpSrcPage, tmpDstPage;

    //set sector bitmap and buffer pointer for copy nand flash page
    tmpSrcPage.SectBitmap = FULL_BITMAP_OF_SUPER_PAGE;
    tmpDstPage.SectBitmap = FULL_BITMAP_OF_SUPER_PAGE;
    tmpSrcPage.MDataPtr = NULL;
    tmpSrcPage.SDataPtr = NULL;

    for(i=0; i<nErrPage; i++)
    {
        //calculate source page and destination page parameter for copy nand page
        LML_CalculatePhyOpPar(&tmpSrcPage, nZoneNum, pBadBlk->PhyBlkNum, i);
        LML_CalculatePhyOpPar(&tmpDstPage, nZoneNum, pNewBlk->PhyBlkNum, i);

        PHY_PageCopyback(&tmpSrcPage, &tmpDstPage);
        //check page copy result
        result = PHY_SynchBank(tmpDstPage.BankNum, SYNC_CHIP_MODE);
        if(result < 0)
        {
            LOGICCTL_DBG("[LOGICCTL_DBG] Copy page failed when restore bad block data!\n");
            return -1;
        }
    }

    return 0;
}
コード例 #2
0
ファイル: logic_ctl.c プロジェクト: mantrid/linux-allwinner
/*
************************************************************************************************************************
*                       CALCLUATE PROCESSING DATA PARAMETER
*
*Description: Calculate the loigcal pages number and the sector bitmap in the page for the sectors
*             that pocessing currently.
*
*Arguments  : nSectNum      the number of the first sector of the sectors need be processed;
*             nSectCnt      the count of the sectors that how many sectors need be processed;
*             pHeadPage     the pointer to the paramter of the head page;
*             pMidPageCnt   the pointer ot the count of full pages;
*             pTailPage     the pointer to the paramter of the tail page.
*
*Return     : calculate sector parameter result;
*               = 0     calculate sector parameter successful;
*               < 0     calcualte sector parameter failed.
************************************************************************************************************************
*/
static __s32 _CalculateSectPar(__u32 nSectNum, __u32 nSectCnt, struct __GlobalLogicPageType_t *pHeadPage,
                                    __u32 *pMidPageCnt, struct __GlobalLogicPageType_t *pTailPage)
{
    __u32   tmpSectCnt, tmpBitmap;

    LOGICCTL_DBG("[LOGICCTL_DBG]: Calculate logical sectors parameter, Lba:0x%x, Cnt:0x%x\n", nSectNum, nSectCnt);

    //initiate the middle page and tail page parameters, because they may be empty
    *pMidPageCnt = 0x00;
    pTailPage->LogicPageNum = 0xffffffff;
    pTailPage->SectorBitmap = 0x00;

    //calculate the head page parameter
    pHeadPage->LogicPageNum = nSectNum / SECTOR_CNT_OF_LOGIC_PAGE;
    tmpSectCnt = nSectCnt + (nSectNum % SECTOR_CNT_OF_LOGIC_PAGE);
    tmpBitmap = (FULL_BITMAP_OF_LOGIC_PAGE << (nSectNum % SECTOR_CNT_OF_LOGIC_PAGE));

    if(tmpSectCnt > SECTOR_CNT_OF_LOGIC_PAGE)
    {
        //set the head page bitmap
        pHeadPage->SectorBitmap = tmpBitmap & FULL_BITMAP_OF_LOGIC_PAGE;

        //calcualte the count of full pages
        tmpSectCnt -= SECTOR_CNT_OF_LOGIC_PAGE;
        while(tmpSectCnt >= SECTOR_CNT_OF_LOGIC_PAGE)
        {
            ++*pMidPageCnt;
            tmpSectCnt -= SECTOR_CNT_OF_LOGIC_PAGE;
        }

        //calculate parameter for the tail page
        if(tmpSectCnt)
        {
            //calcualte the tail page sector bitmap
            pTailPage->SectorBitmap = FULL_BITMAP_OF_LOGIC_PAGE >> (SECTOR_CNT_OF_LOGIC_PAGE - tmpSectCnt);

            //calculate the number of the tail page
            pTailPage->LogicPageNum = pHeadPage->LogicPageNum + *pMidPageCnt + 1;
        }
    }
コード例 #3
0
ファイル: bad_manage.c プロジェクト: djytw/bootloader
/*
************************************************************************************************************************
*                       WRITE BAD FLAG TO BAD BLOCK
*
*Description: Write bad block flag to bad block.
*
*Arguments  : pBadBlk   the pointer to the bad physical block parameter.
*
*Return     : mark bad block result;
*               = 0     mark bad block successful;
*               = -1    mark bad block failed.
************************************************************************************************************************
*/
static __s32 _MarkBadBlk(struct __SuperPhyBlkType_t *pBadBlk, __u32 nZoneNum)
{
    __s32   i;
	__s32   ret;
    struct __PhysicOpPara_t tmpPage;
    struct __NandUserData_t tmpSpare[2];

	//add by neil 20101201
	/* erase bad blcok */
	ret = LML_VirtualBlkErase(nZoneNum, pBadBlk->PhyBlkNum);
	if(ret)
	{
		LOGICCTL_DBG("[LOGICCTL_DBG] erase bad block fail!\n");
	}


    //set the spare area data for write
    MEMSET((void *)tmpSpare, 0x00, 2*sizeof(struct __NandUserData_t));

    tmpPage.SectBitmap = FULL_BITMAP_OF_SUPER_PAGE;
    tmpPage.MDataPtr = LML_TEMP_BUF;
    tmpPage.SDataPtr = (void *)tmpSpare;

    //write the bad flag in ervery single physical block of the super block
    for(i=0; i<INTERLEAVE_BANK_CNT; i++)
    {
        //write the bad flag in the first page of the physical block
        LML_CalculatePhyOpPar(&tmpPage, nZoneNum, pBadBlk->PhyBlkNum, i);
        LML_VirtualPageWrite(&tmpPage);
        PHY_SynchBank(tmpPage.BankNum, SYNC_CHIP_MODE);

        //write the bad flag in the last page of the physical block
        LML_CalculatePhyOpPar(&tmpPage, nZoneNum, pBadBlk->PhyBlkNum, PAGE_CNT_OF_SUPER_BLK - INTERLEAVE_BANK_CNT + i);
        LML_VirtualPageWrite(&tmpPage);
        PHY_SynchBank(tmpPage.BankNum, SYNC_CHIP_MODE);
    }

    return 0;
}
コード例 #4
0
ファイル: mapping_base.c プロジェクト: STPJ/linux-3.4-sunxi
/*
************************************************************************************************************************
*                       GET LOG PAGE FOR WRITE
*
*Description: Get a log page for write.
*
*Arguments  : nBlk      the logical block number of the log block;
*             nPage     the number of the logical page, which page need log page;
*             pLogPage  the pointer to the log page number, for return value;
*             pLogPst   the pointer to the position of the log block in the log block table.
*
*Return     : get log page result.
*               = 0     get log page for write successful;
*               =-1     get log page for write failed.
************************************************************************************************************************
*/
static __s32 _GetLogPageForWrite(__u32 nBlk, __u32 nPage, __u16 *pLogPage, __u32 *pLogPst)
{
    __s32   result, tmpLogPst;
    __u16   tmpPage, tempBank;
    struct __PhysicOpPara_t tmpPhyPage;
    struct __NandUserData_t tmpSpare[2];

    tmpLogPst = _GetLogBlkPst(nBlk);
    if(tmpLogPst < 0)
    {
        //get log block position failed, there is no such log block, need create a new one
        result = _CreateNewLogBlk(nBlk, (__u32 *)&tmpLogPst);
        if(result < 0)
        {
            MAPPING_ERR("[MAPPING_ERR] Create new log block failed!\n");
            return -1;
        }
    }

    //need swap the page mapping table to ram which is accessing currently
    result = PMM_SwitchMapTbl(tmpLogPst);
    if(result < 0)
    {
        MAPPING_ERR("[MAPPING_ERR] Switch page mapping table failed when get log page! Err:0x%x\n", result);
        return -1;
    }

    //need get log page by write mode,
    tmpPage = LOG_BLK_TBL[tmpLogPst].LastUsedPage;

	if(SUPPORT_ALIGN_NAND_BNK)
    {
        if(tmpPage == 0xffff)
        {
            //the log block is empty, need get log page in the first page line
            tmpPage = nPage % INTERLEAVE_BANK_CNT;
        }
        else
        {
            //need bank align, the log page and the data page should be in the same bank
            if((nPage % INTERLEAVE_BANK_CNT) > (tmpPage % INTERLEAVE_BANK_CNT))
            {
                //get the log page in the same page line with last used page
                tmpPage = tmpPage + ((nPage % INTERLEAVE_BANK_CNT) - (tmpPage % INTERLEAVE_BANK_CNT));
            }
            else
            {
                //need get the log page in the next page line of the last used page
                tmpPage = tmpPage + (nPage % INTERLEAVE_BANK_CNT) + (INTERLEAVE_BANK_CNT - (tmpPage % INTERLEAVE_BANK_CNT));
            }
        }
    }
    else
    {

        //use the page which is the next of the last used page
        tmpPage = tmpPage + 1;
    }

	if((SUPPORT_LOG_BLOCK_MANAGE)&&(LOG_BLK_TBL[tmpLogPst].LogBlkType == LSB_TYPE))
	{
		DBUG_MSG("[DBUG_MSG] _GetLogPageForWrite, select bak log block\n");

		if(SUPPORT_ALIGN_NAND_BNK)
		{
			tempBank = tmpPage%INTERLEAVE_BANK_CNT;
			tmpPage =PMM_CalNextLogPage(tmpPage);
			while(tmpPage%INTERLEAVE_BANK_CNT != tempBank)
			{
				tmpPage++;
				tmpPage =PMM_CalNextLogPage(tmpPage);
				if(tmpPage>=PAGE_CNT_OF_SUPER_BLK)
					break;
			}
		}
		else
		{
			tmpPage =PMM_CalNextLogPage(tmpPage);
		}

		if((tmpPage >= PAGE_CNT_OF_SUPER_BLK)&&(LOG_BLK_TBL[tmpLogPst].WriteBlkIndex == 0))
		{
			LOG_BLK_TBL[tmpLogPst].WriteBlkIndex = 1;
			tmpPage = tmpPage - PAGE_CNT_OF_SUPER_BLK;
		}
		if(LOG_BLK_TBL[tmpLogPst].WriteBlkIndex == 1)
			DBUG_MSG("[DBUG_MSG] _GetLogPageForWrite, log block index: %x, log block num: %x, page: %x \n", LOG_BLK_TBL[tmpLogPst].WriteBlkIndex, LOG_BLK_TBL[tmpLogPst].PhyBlk1.PhyBlkNum, tmpPage);
		else
			DBUG_MSG("[DBUG_MSG] _GetLogPageForWrite, log block index: %x, log block num: %x, page: %x \n", LOG_BLK_TBL[tmpLogPst].WriteBlkIndex, LOG_BLK_TBL[tmpLogPst].PhyBlk.PhyBlkNum, tmpPage);
	}

__CHECK_WRITE_LOGICAL_INFO_OF_LOG_BLOCK:
    //check if need write the logical information in the first page of the log block
    if((LOG_BLK_TBL[tmpLogPst].LastUsedPage == 0xffff) && (tmpPage != 0))
    {
        //get logical information from the data block
        LML_CalculatePhyOpPar(&tmpPhyPage, CUR_MAP_ZONE, DATA_BLK_TBL[nBlk].PhyBlkNum, 0);
        tmpPhyPage.SectBitmap = 0x03;
        tmpPhyPage.MDataPtr = LML_TEMP_BUF;
        tmpPhyPage.SDataPtr = (void *)tmpSpare;
        LML_VirtualPageRead(&tmpPhyPage);

		//if((SUPPORT_LOG_BLOCK_MANAGE)&&(LOG_BLK_TBL[tmpLogPst].LogBlkType == LSB_TYPE))
		//{
		//	PRINT("_GetLogPageForWrite log %x page 0, data age: %x, log age: %x\n", LOG_BLK_TBL[tmpLogPst].WriteBlkIndex, tmpSpare[0].PageStatus, tmpSpare[0].PageStatus+1);
		//}

        tmpSpare[0].BadBlkFlag = 0xff;
        tmpSpare[1].BadBlkFlag = 0xff;
        tmpSpare[0].LogicInfo = ((CUR_MAP_ZONE % ZONE_CNT_OF_DIE)<<10) | nBlk;
        tmpSpare[1].LogicInfo = ((CUR_MAP_ZONE % ZONE_CNT_OF_DIE)<<10) | nBlk;
        tmpSpare[0].LogicPageNum = 0xffff;
        tmpSpare[1].LogicPageNum = 0xffff;
        tmpSpare[0].PageStatus =  tmpSpare[0].PageStatus + 1;
        tmpSpare[1].PageStatus = tmpSpare[0].PageStatus;
		if((SUPPORT_LOG_BLOCK_MANAGE)&&(LOG_BLK_TBL[tmpLogPst].LogBlkType == LSB_TYPE))
		{
			tmpSpare[0].LogType = LSB_TYPE|(LOG_BLK_TBL[tmpLogPst].WriteBlkIndex<<4);
			tmpSpare[1].LogType = LSB_TYPE|(LOG_BLK_TBL[tmpLogPst].WriteBlkIndex<<4);
		}
		else
		{
			tmpSpare[0].LogType = 0xff;
			tmpSpare[1].LogType = 0xff;
		}

       //write the logical information to the spare area of the data block
       	if((SUPPORT_LOG_BLOCK_MANAGE)&&(LOG_BLK_TBL[tmpLogPst].LogBlkType == LSB_TYPE))
       	{
       		DBUG_MSG("[DBUG] _GetLogPageForWrite, write the logical information to log page 0, writeblkindex: %x\n", LOG_BLK_TBL[tmpLogPst].WriteBlkIndex);
       		LML_CalculatePhyOpPar(&tmpPhyPage, CUR_MAP_ZONE, LOG_BLK_TBL[tmpLogPst].PhyBlk.PhyBlkNum, 0);
       	}
		else
        	LML_CalculatePhyOpPar(&tmpPhyPage, CUR_MAP_ZONE, LOG_BLK_TBL[tmpLogPst].PhyBlk.PhyBlkNum, 0);

		tmpPhyPage.SectBitmap = FULL_BITMAP_OF_SUPER_PAGE;
        result = LML_VirtualPageWrite(&tmpPhyPage);
        if(result < 0)
        {
            LOGICCTL_ERR("[MAPPING_ERR] Physical write module failed when write logical information, Err:0x%x!\n", result);
            return -1;
        }

        result = PHY_SynchBank(tmpPhyPage.BankNum, SYNC_CHIP_MODE);
        if(result < 0)
        {
            //the last write operation on current bank is failed, the block is bad, need proccess it
            LOGICCTL_DBG("[LOGICCTL_DBG] Find a bad block when write logical page! bank:0x%x, block:0x%x, page:0x%x\n",
                    tmpPhyPage.BankNum, tmpPhyPage.BlkNum, tmpPhyPage.PageNum);

            //process the bad block
            result = LML_BadBlkManage(&LOG_BLK_TBL[tmpLogPst].PhyBlk, CUR_MAP_ZONE, 0, &LOG_BLK_TBL[tmpLogPst].PhyBlk);
            if(result < 0)
            {
                LOGICCTL_ERR("[MAPPING_ERR] Bad block process failed when get log page for write, Err:0x%x!\n", result);
                return -1;
            }

           goto __CHECK_WRITE_LOGICAL_INFO_OF_LOG_BLOCK;
        }
    }

    //set the log page number for return
    *pLogPage = tmpPage;
    *pLogPst = tmpLogPst;

    return 0;
}
コード例 #5
0
ファイル: mapping_base.c プロジェクト: STPJ/linux-3.4-sunxi
/*
************************************************************************************************************************
*                       CREATE A NEW LOG BLOCK
*
*Description: Create a new log block.
*
*Arguments  : nBlk      the logical block number of the log block;
*             pLogPst   the pointer to the log block position in the log block table.
*
*Return     : create new log block result.
*               = 0     create new log block successful;
*               =-1     create new log block failed.
************************************************************************************************************************
*/
static __s32 _CreateNewLogBlk(__u32 nBlk, __u32 *pLogPst)
{
    __s32   i, result, LogBlkType,tmpPst=-1;
    __u16   tmpLogAccessAge = 0xffff;
    struct __SuperPhyBlkType_t tmpFreeBlk, tmpFreeBlk1;
    struct __PhysicOpPara_t tmpPhyPage;
    struct __NandUserData_t tmpSpare[2];

    #if CFG_SUPPORT_WEAR_LEVELLING

    //check if need do wear-levelling
    if(BLK_ERASE_CNTER >= WEAR_LEVELLING_FREQUENCY)
    {
        LML_WearLevelling();
    }

    #endif
    //try to search an empty item in the log block table
    for(i=0; i<LOG_BLK_CNT_OF_ZONE; i++)
    {
        if(LOG_BLK_TBL[i].LogicBlkNum == 0xffff)
        {
            //find a empty item
            tmpPst = i;
            break;
        }
    }

    //there is no empty item in the log block table, need merge a log block
    if(tmpPst == -1)
    {
        //check if there is some full log block
        for(i=0; i<LOG_BLK_CNT_OF_ZONE; i++)
        {
            if(LOG_BLK_TBL[i].LastUsedPage == PAGE_CNT_OF_SUPER_BLK-1)
            {
                tmpPst = i;
                break;
            }
        }

        if(tmpPst == -1)
        {
            //there is no full log block, look for an oldest log block to merge
            for(i=0; i<LOG_BLK_CNT_OF_ZONE; i++)
            {
                if(LOG_ACCESS_AGE[i] < tmpLogAccessAge)
                {
                    tmpLogAccessAge = LOG_ACCESS_AGE[i];
                    tmpPst = i;
                }
            }
        }

        //switch the page mapping table for merge the log block
        result = PMM_SwitchMapTbl(tmpPst);
        if(result < 0)
        {
            MAPPING_ERR("[MAPPING_ERR] Switch page mapping table failed when create new log block! Err:0x%x\n", result);
            return -1;
        }

        //merge the log block with normal type, to make an empty item
        result = LML_MergeLogBlk(NORMAL_MERGE_MODE, LOG_BLK_TBL[tmpPst].LogicBlkNum);
        if(result < 0)
        {
            //merge log block failed, report error
            MAPPING_ERR("[MAPPING_ERR] Merge log block failed when create new log block! Err:0x%x\n", result);
            return -1;
        }
    }

	LogBlkType = BMM_CalLogBlkType(nBlk);

	if((SUPPORT_LOG_BLOCK_MANAGE)&&(LogBlkType == LSB_TYPE))
	{
		DBUG_MSG("[DBUG_MSG] _CreateNewLogBlk, select bak log block\n");

		//get a free block to create a new log block
	    result = BMM_GetFreeBlk(LOWEST_EC_TYPE, &tmpFreeBlk);
	    if(result < 0)
	    {
	        MAPPING_ERR("[MAPPING_ERR] Get free block failed when create new log block!\n");
	        return -1;
	    }

		//get a free block to create a new log block
	    result = BMM_GetFreeBlk(LOWEST_EC_TYPE, &tmpFreeBlk1);
	    if(result < 0)
	    {
	        MAPPING_ERR("[MAPPING_ERR] Get free block failed when create new log block!\n");
	        return -1;
	    }

		//DBUG_INF("[DBUG] _CreateNewLogBlk, logic: %x, logblk0: %x, logblk1:%x \n", nBlk, tmpFreeBlk.PhyBlkNum, tmpFreeBlk1.PhyBlkNum);

	    //make a new log item in the log block table
	    LOG_BLK_TBL[tmpPst].LogicBlkNum = nBlk;
	    LOG_BLK_TBL[tmpPst].LastUsedPage = 0xffff;
		LOG_BLK_TBL[tmpPst].LogBlkType = LogBlkType;
		LOG_BLK_TBL[tmpPst].WriteBlkIndex = 0;
		LOG_BLK_TBL[tmpPst].ReadBlkIndex = 0;
	    LOG_BLK_TBL[tmpPst].PhyBlk = tmpFreeBlk;
		LOG_BLK_TBL[tmpPst].PhyBlk1 = tmpFreeBlk1;
	    //set the return vaule of the log position
	    *pLogPst = tmpPst;
	}
	else
	{
	    //get a free block to create a new log block
	    result = BMM_GetFreeBlk(LOWEST_EC_TYPE, &tmpFreeBlk);
	    if(result < 0)
	    {
	        MAPPING_ERR("[MAPPING_ERR] Get free block failed when create new log block!\n");
	        return -1;
	    }

	    //make a new log item in the log block table
	    LOG_BLK_TBL[tmpPst].LogicBlkNum = nBlk;
	    LOG_BLK_TBL[tmpPst].LastUsedPage = 0xffff;
		LOG_BLK_TBL[tmpPst].LogBlkType = LogBlkType;
		LOG_BLK_TBL[tmpPst].WriteBlkIndex = 0;
		LOG_BLK_TBL[tmpPst].ReadBlkIndex = 0;
	    LOG_BLK_TBL[tmpPst].PhyBlk = tmpFreeBlk;
	    //set the return vaule of the log position
	    *pLogPst = tmpPst;
	}


__CHECK_LOGICAL_INFO_OF_DATA_BLOCK:
    //check if the data block is an empty block, if so, need update the logic information in the spare area
    LML_CalculatePhyOpPar(&tmpPhyPage, CUR_MAP_ZONE, DATA_BLK_TBL[nBlk].PhyBlkNum, 0);
    tmpPhyPage.SectBitmap = 0x03;
    tmpPhyPage.MDataPtr = LML_TEMP_BUF;
    tmpPhyPage.SDataPtr = (void *)tmpSpare;
    LML_VirtualPageRead(&tmpPhyPage);

    if(tmpSpare[0].LogicInfo == 0xffff)
    {
        tmpSpare[0].BadBlkFlag = 0xff;
        tmpSpare[1].BadBlkFlag = 0xff;
        tmpSpare[0].LogicInfo = ((CUR_MAP_ZONE % ZONE_CNT_OF_DIE)<<10) | nBlk;
        tmpSpare[1].LogicInfo = ((CUR_MAP_ZONE % ZONE_CNT_OF_DIE)<<10) | nBlk;
        tmpSpare[0].LogicPageNum = 0xffff;
        tmpSpare[1].LogicPageNum = 0xffff;
        tmpSpare[0].PageStatus = 0xff;
        tmpSpare[1].PageStatus = 0xff;

        //write the logical information to the spare area of the data block
        tmpPhyPage.SectBitmap = FULL_BITMAP_OF_SUPER_PAGE;
        result = LML_VirtualPageWrite(&tmpPhyPage);
        if(result < 0)
        {
            LOGICCTL_ERR("[MAPPING_ERR] Physical write module failed when write logical information, Err:0x%x!\n", result);
            return -1;
        }

        result = PHY_SynchBank(tmpPhyPage.BankNum, SYNC_CHIP_MODE);
        if(result < 0)
        {
            //the last write operation on current bank is failed, the block is bad, need proccess it
            LOGICCTL_DBG("[LOGICCTL_DBG] Find a bad block when write logical page! bank:0x%x, block:0x%x, page:0x%x\n",
                    tmpPhyPage.BankNum, tmpPhyPage.BlkNum, tmpPhyPage.PageNum);

            //process the bad block
            result = LML_BadBlkManage(&DATA_BLK_TBL[nBlk], CUR_MAP_ZONE, 0, &tmpFreeBlk);
            if(result < 0)
            {
                LOGICCTL_ERR("[MAPPING_ERR] Bad block process failed when create new log block, Err:0x%x!\n", result);
                return -1;
            }
            DATA_BLK_TBL[nBlk] = tmpFreeBlk;

            goto __CHECK_LOGICAL_INFO_OF_DATA_BLOCK;
        }
    }

    return 0;
}
コード例 #6
0
/*
************************************************************************************************************************
*                   NAND FLASH LOGIC MANAGE LAYER WEAR-LEVELLING
*
*Description: Equate the erase cycles among all physical blocks.
*
*Arguments  : none
*
*Return     : do wear-levelling result;
*               = 0     do wear-levelling successful;
*               = -1    do wear-levelling failed.
*
*Notes      : The erase cycle of a physical block is limited, if the erase cycle overun this
*             limit, the physical block may be invalid. so a policy is needed to equate the
*             millions of erase cycles to ervery physical block.
************************************************************************************************************************
*/
__s32 LML_WearLevelling(void)
{
    #if CFG_SUPPORT_WEAR_LEVELLING

    __s32   i, result;

    __u32   tmpLogicBlk;
    __u16   tmpLowEc = 0xffff;
    struct __SuperPhyBlkType_t tmpFreeBlk, tmpDataBlk;
    struct __NandUserData_t tmpSpare[2];
    struct __PhysicOpPara_t tmpSrcPage, tmpDstPage;
    BLK_ERASE_CNTER = 0;

    //scan the data block table, to look for a physical block with lowest erase count
    for(i=DATA_BLK_CNT_OF_ZONE-1; i>=0; i--)
    {
        if(DATA_BLK_TBL[i].BlkEraseCnt < tmpLowEc)
        {
            tmpLowEc = DATA_BLK_TBL[i].BlkEraseCnt;
            tmpLogicBlk = i;
        }
    }

    //get a free block which has the highest erase count
    result = BMM_GetFreeBlk(HIGHEST_EC_TYPE, &tmpFreeBlk);
    if(result < 0)
    {
        LOGICCTL_ERR("[LOGICCTL_ERR] Get free block failed when do wear-levelling!\n");
        return -1;
    }

    //clear the block erase counter
    BLK_ERASE_CNTER = 0;

    if(tmpLowEc >= tmpFreeBlk.BlkEraseCnt)
    {
        if(tmpLowEc == 0xffff)
        {
            //the lowest erase count reach the highest value, clear erase count of all physical block
            for(i=0; i<DATA_BLK_CNT_OF_ZONE; i++)
            {
                //clear the erase count for the data block
                DATA_BLK_TBL[i].BlkEraseCnt = 0x00;
            }

            for(i=0; i<FREE_BLK_CNT_OF_ZONE; i++)
            {
                //clear the erase count for the free block
                if(FREE_BLK_TBL[i].PhyBlkNum != 0xffff)
                {
                    FREE_BLK_TBL[i].BlkEraseCnt = 0x00;
                }
            }

            for(i=0; i<MAX_LOG_BLK_CNT; i++)
            {
                //clear the erase count for the log block
                if(LOG_BLK_TBL[i].LogicBlkNum != 0xffff)
                {
                    LOG_BLK_TBL[i].PhyBlk.BlkEraseCnt = 0x00;
                }
            }
        }

        BMM_SetFreeBlk(&tmpFreeBlk);

        return 0;
    }

    BMM_GetDataBlk(tmpLogicBlk, &tmpDataBlk);
    result = BMM_GetLogBlk(tmpLogicBlk, NULL);
    if(result < 0)
    {
        //check if the data block is empty
        LML_CalculatePhyOpPar(&tmpSrcPage, CUR_MAP_ZONE, tmpDataBlk.PhyBlkNum, 0);
        tmpSrcPage.SectBitmap = 0x03;
        tmpSrcPage.MDataPtr = LML_TEMP_BUF;
        tmpSrcPage.SDataPtr = (void *)tmpSpare;
        LML_VirtualPageRead(&tmpSrcPage);

        if(tmpSpare[0].LogicInfo != 0xffff)
        {
            //need copy data from the data block to the free block
            tmpSrcPage.SectBitmap = FULL_BITMAP_OF_SUPER_PAGE;
            tmpSrcPage.MDataPtr = NULL;
            tmpSrcPage.SDataPtr = NULL;

            tmpDstPage.SectBitmap = FULL_BITMAP_OF_SUPER_PAGE;
            tmpDstPage.MDataPtr = NULL;
            tmpDstPage.SDataPtr = NULL;

            for(i=0; i<PAGE_CNT_OF_SUPER_BLK; i++)
            {
                LML_CalculatePhyOpPar(&tmpSrcPage, CUR_MAP_ZONE, tmpDataBlk.PhyBlkNum, i);
                LML_CalculatePhyOpPar(&tmpDstPage, CUR_MAP_ZONE, tmpFreeBlk.PhyBlkNum, i);

                PHY_PageCopyback(&tmpSrcPage, &tmpDstPage);
                //check page copy result
                result = PHY_SynchBank(tmpDstPage.BankNum, SYNC_CHIP_MODE);
                if(result < 0)
                {
                    LOGICCTL_DBG("[LOGICCTL_DBG] Copy page failed when doing wear-levelling!\n");
                    result = LML_BadBlkManage(&tmpFreeBlk, CUR_MAP_ZONE, 0, NULL);
                    if(result < 0)
                    {
                        LOGICCTL_ERR("[LOGICCTL_ERR] Bad block manage failed when doing wear-levelling!\n");
                        return -1;
                    }

                    return 0;
                }
            }
        }

        //set the data block item by the free block
        BMM_SetDataBlk(tmpLogicBlk, &tmpFreeBlk);

        if(tmpSpare[0].LogicInfo != 0xffff)
        {
            //erase the data block to a new free block
            result = LML_VirtualBlkErase(CUR_MAP_ZONE, tmpDataBlk.PhyBlkNum);
            if(result < 0)
            {
                LOGICCTL_DBG("[LOGICCTL_DBG] Erase super block failed when doing wear-levelling!\n");
                result = LML_BadBlkManage(&tmpDataBlk, CUR_MAP_ZONE, 0, NULL);
                if(result < 0)
                {
                    LOGICCTL_ERR("[LOGICCTL_ERR] Bad block manage failed when doing wear-levelling!\n");
                   return -1;
                }

                return 0;
            }
        }

        //set the the data block to free block table
        tmpDataBlk.BlkEraseCnt++;
        BMM_SetFreeBlk(&tmpDataBlk);
    }
    else
    {
        //set the free block back to free table
        BMM_SetFreeBlk(&tmpFreeBlk);
    }

    #endif
    return 0;
}