/drivers/block/sun3i_nand/src/logic/merge.c
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