/* ************************************************************************************************************************ * 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; }
/* ************************************************************************************************************************ * 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; } }
/* ************************************************************************************************************************ * 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; }
/* ************************************************************************************************************************ * 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; }
/* ************************************************************************************************************************ * 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; }
/* ************************************************************************************************************************ * 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; }