/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

  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. #include "../include/nand_logic.h"
  23. extern struct __NandDriverGlobal_t NandDriverInfo;
  24. __s32 _copy_page0(__u32 SrcBlk,__u16 SrcDataPage,__u32 DstBlk,__u8 SeqPlus)
  25. {
  26. __u8 seq;
  27. __u16 LogicInfo;
  28. struct __NandUserData_t UserData[2];
  29. struct __PhysicOpPara_t SrcParam,DstParam;
  30. SrcParam.MDataPtr = DstParam.MDataPtr = LML_TEMP_BUF;
  31. SrcParam.SDataPtr = DstParam.SDataPtr = (void *)&UserData;
  32. MEMSET((void *)&UserData,0xff,sizeof(struct __NandUserData_t) * 2);
  33. /*get seq and logicinfo*/
  34. SrcParam.SectBitmap = 0x3;
  35. LML_CalculatePhyOpPar(&SrcParam,CUR_MAP_ZONE, SrcBlk, 0);
  36. if (LML_VirtualPageRead(&SrcParam) < 0){
  37. LOGICCTL_ERR("_copy_page0 : read user data err\n");
  38. return NAND_OP_FALSE;
  39. }
  40. seq = UserData[0].PageStatus;
  41. LogicInfo = UserData[0].LogicInfo;
  42. /*copy main data */
  43. SrcParam.SectBitmap = DstParam.SectBitmap = FULL_BITMAP_OF_SUPER_PAGE;
  44. LML_CalculatePhyOpPar(&SrcParam, CUR_MAP_ZONE, SrcBlk, SrcDataPage);
  45. LML_CalculatePhyOpPar(&DstParam, CUR_MAP_ZONE, DstBlk, 0);
  46. if (LML_VirtualPageRead(&SrcParam) < 0){
  47. LOGICCTL_ERR("_copy_page0 : read main data err\n");
  48. return NAND_OP_FALSE;
  49. }
  50. UserData[0].LogicInfo = LogicInfo;
  51. UserData[0].PageStatus = seq + SeqPlus;
  52. if (NAND_OP_TRUE != LML_VirtualPageWrite(&DstParam)){
  53. LOGICCTL_ERR("_copy_page0 : write err\n");
  54. return NAND_OP_FALSE;
  55. }
  56. return NAND_OP_TRUE;
  57. }
  58. /*!
  59. *
  60. * \par Description:
  61. * This function copy valuable data from datablk to logblk,then change datablk to freeblk ,change logblk to datablk.
  62. *
  63. * \param [in] LogNum,serial number within log block space
  64. * \return sucess or failed.
  65. * \note this function was called when log block is in order,that is to say physical
  66. * page number is same with logical page number.
  67. **/
  68. __s32 _log2data_swap_merge(__u32 nlogical)
  69. {
  70. __u16 LastUsedPage,SuperPage;
  71. struct __SuperPhyBlkType_t DataBlk;
  72. struct __LogBlkType_t LogBlk;
  73. struct __PhysicOpPara_t SrcParam,DstParam;
  74. /* init info of data block and log block*/
  75. BMM_GetDataBlk(nlogical, &DataBlk);
  76. BMM_GetLogBlk(nlogical, &LogBlk);
  77. LastUsedPage = LogBlk.LastUsedPage;
  78. /*copy data from data block to log block*/
  79. for (SuperPage = LastUsedPage + 1; SuperPage < PAGE_CNT_OF_SUPER_BLK; SuperPage++){
  80. /*set source and destinate address*/
  81. LML_CalculatePhyOpPar(&SrcParam,CUR_MAP_ZONE, DataBlk.PhyBlkNum, SuperPage);
  82. LML_CalculatePhyOpPar(&DstParam,CUR_MAP_ZONE, LogBlk.PhyBlk.PhyBlkNum, SuperPage);
  83. if (NAND_OP_TRUE != PHY_PageCopyback(&SrcParam,&DstParam)){
  84. LOGICCTL_ERR("swap merge : copy back err\n");
  85. return NAND_OP_FALSE;
  86. }
  87. if (NAND_OP_TRUE != PHY_SynchBank(DstParam.BankNum, SYNC_BANK_MODE)){
  88. struct __SuperPhyBlkType_t SubBlk;
  89. if (NAND_OP_TRUE != LML_BadBlkManage(&LogBlk.PhyBlk,CUR_MAP_ZONE,SuperPage,&SubBlk)){
  90. LOGICCTL_ERR("swap merge : bad block manage err after copy back\n");
  91. return NAND_OP_FALSE;
  92. }
  93. LogBlk.PhyBlk = SubBlk;
  94. SuperPage -= 1;
  95. }
  96. }
  97. /*move log block to data block*/
  98. BMM_SetDataBlk(nlogical, &LogBlk.PhyBlk);
  99. /*clear log block item*/
  100. MEMSET(&LogBlk, 0xff, sizeof(struct __LogBlkType_t));
  101. BMM_SetLogBlk(nlogical, &LogBlk);
  102. /*erase data block*/
  103. if ( NAND_OP_TRUE != LML_VirtualBlkErase(CUR_MAP_ZONE, DataBlk.PhyBlkNum)){
  104. if (NAND_OP_TRUE != LML_BadBlkManage(&DataBlk,CUR_MAP_ZONE,0,NULL)){
  105. LOGICCTL_ERR("swap merge : bad block manage err erase data block\n");
  106. return NAND_OP_FALSE;
  107. }
  108. }
  109. /*move erased data block to free block*/
  110. if (DataBlk.BlkEraseCnt < 0xffff)
  111. DataBlk.BlkEraseCnt ++;
  112. BMM_SetFreeBlk(&DataBlk);
  113. /*clear page map table*/
  114. PMM_ClearCurMapTbl();
  115. return NAND_OP_TRUE;
  116. }
  117. /*!
  118. *
  119. * \par Description:
  120. * This function move valuable data from log block to free block,then replace them.
  121. *
  122. * \param [in] LogNum,serial number within log block space
  123. * \return sucess or failed.
  124. * \note this function was called when log block is full, and valid pages is less than half of one block.
  125. **/
  126. __s32 _free2log_move_merge(__u32 nlogical)
  127. {
  128. __u8 bank;
  129. __u16 LastUsedPage,SuperPage;
  130. __u16 SrcPage,DstPage;
  131. struct __SuperPhyBlkType_t FreeBlk;
  132. struct __LogBlkType_t LogBlk;
  133. struct __PhysicOpPara_t SrcParam,DstParam;
  134. #if (!CFG_SUPPORT_ALIGN_NAND_BNK)
  135. struct __NandUserData_t UserData[2];
  136. #endif
  137. /*init info of log block , and get one free block */
  138. BMM_GetLogBlk(nlogical, &LogBlk);
  139. if (NAND_OP_TRUE != BMM_GetFreeBlk(LOWEST_EC_TYPE, &FreeBlk))
  140. return NAND_OP_FALSE;
  141. SrcParam.MDataPtr = DstParam.MDataPtr = NULL;
  142. SrcParam.SDataPtr = DstParam.SDataPtr = NULL;
  143. SrcParam.SectBitmap = DstParam.SectBitmap = FULL_BITMAP_OF_SUPER_PAGE;
  144. #if (CFG_SUPPORT_ALIGN_NAND_BNK)
  145. redo:
  146. /*copy data bank by bank, for copy-back using*/
  147. LastUsedPage = 0;
  148. for (bank = 0; bank < INTERLEAVE_BANK_CNT; bank++)
  149. {
  150. DstPage = bank;
  151. for (SuperPage = bank; SuperPage < PAGE_CNT_OF_SUPER_BLK; SuperPage+= INTERLEAVE_BANK_CNT)
  152. {
  153. SrcPage = PMM_GetCurMapPage(SuperPage);
  154. if (SrcPage != 0xffff)
  155. {
  156. /*set source and destinate address*/
  157. LML_CalculatePhyOpPar(&SrcParam,CUR_MAP_ZONE, LogBlk.PhyBlk.PhyBlkNum, SrcPage);
  158. LML_CalculatePhyOpPar(&DstParam,CUR_MAP_ZONE, FreeBlk.PhyBlkNum, DstPage);
  159. if (DstPage == 0)
  160. {
  161. if ( NAND_OP_FALSE == _copy_page0(LogBlk.PhyBlk.PhyBlkNum,SrcPage,FreeBlk.PhyBlkNum,0))
  162. {
  163. LOGICCTL_ERR("move merge : copy page 0 err1\n");
  164. return NAND_OP_FALSE;
  165. }
  166. }
  167. else
  168. {
  169. if (NAND_OP_TRUE != PHY_PageCopyback(&SrcParam,&DstParam))
  170. {
  171. LOGICCTL_ERR("move merge : copy back err\n");
  172. return NAND_OP_FALSE;
  173. }
  174. }
  175. if (NAND_OP_TRUE != PHY_SynchBank(DstParam.BankNum, SYNC_BANK_MODE))
  176. {
  177. struct __SuperPhyBlkType_t SubBlk;
  178. if (NAND_OP_TRUE != LML_BadBlkManage(&FreeBlk,CUR_MAP_ZONE,0,&SubBlk))
  179. {
  180. LOGICCTL_ERR("move merge : bad block manage err after copy back\n");
  181. return NAND_OP_FALSE;
  182. }
  183. FreeBlk = SubBlk;
  184. goto redo;
  185. }
  186. PMM_SetCurMapPage(SuperPage,DstPage);
  187. DstPage += INTERLEAVE_BANK_CNT;
  188. }
  189. }
  190. /*if bank 0 is empty, need write mange info in page 0*/
  191. if ((bank == 0) && (DstPage == 0))
  192. {
  193. if ( NAND_OP_FALSE == _copy_page0(LogBlk.PhyBlk.PhyBlkNum,0,FreeBlk.PhyBlkNum,0))
  194. {
  195. LOGICCTL_ERR("move merge : copy page 0 err2\n");
  196. return NAND_OP_FALSE;
  197. }
  198. LML_CalculatePhyOpPar(&DstParam, CUR_MAP_ZONE, FreeBlk.PhyBlkNum, 0);
  199. if (NAND_OP_TRUE != PHY_SynchBank(DstParam.BankNum, SYNC_BANK_MODE))
  200. {
  201. struct __SuperPhyBlkType_t SubBlk;
  202. if (NAND_OP_TRUE != LML_BadBlkManage(&FreeBlk,CUR_MAP_ZONE,0,&SubBlk))
  203. {
  204. LOGICCTL_ERR("move merge : bad block manage err after copy back\n");
  205. return NAND_OP_FALSE;
  206. }
  207. FreeBlk = SubBlk;
  208. goto redo;
  209. }
  210. }
  211. /*reset LastUsedPage*/
  212. if ((DstPage - INTERLEAVE_BANK_CNT) > LastUsedPage)
  213. {
  214. LastUsedPage = DstPage - INTERLEAVE_BANK_CNT;
  215. }
  216. }
  217. #else
  218. /*copy data page by page*/
  219. DstPage = 0;
  220. for (SuperPage = 0; SuperPage < PAGE_CNT_OF_LOGIC_BLK; SuperPage++)
  221. {
  222. SrcPage = PMM_GetCurMapPage(SuperPage);
  223. if (SrcPage != 0xffff)
  224. {
  225. /*set source and destinate address*/
  226. LML_CalculatePhyOpPar(&SrcParam,CUR_MAP_ZONE, LogBlk.PhyBlk.PhyBlkNum, SrcPage);
  227. LML_CalculatePhyOpPar(&DstParam,CUR_MAP_ZONE, FreeBlk.PhyBlkNum, DstPage);
  228. if (0 == DstPage)
  229. {
  230. if ( NAND_OP_FALSE == _copy_page0(LogBlk.PhyBlk.PhyBlkNum,SrcPage,FreeBlk.PhyBlkNum,0))
  231. {
  232. LOGICCTL_ERR("move merge : copy page 0 err1\n");
  233. return NAND_OP_FALSE;
  234. }
  235. }
  236. else
  237. {
  238. SrcParam.MDataPtr = DstParam.MDataPtr = LML_TEMP_BUF;
  239. SrcParam.SDataPtr = DstParam.SDataPtr = (void *)&UserData;
  240. MEMSET((void *)&UserData,0xff,sizeof(struct __NandUserData_t) * 2);
  241. SrcParam.SectBitmap = DstParam.SectBitmap = FULL_BITMAP_OF_SUPER_PAGE;
  242. if (LML_VirtualPageRead(&SrcParam) < 0){
  243. LOGICCTL_ERR("move merge : read main data err\n");
  244. return NAND_OP_FALSE;
  245. }
  246. if (NAND_OP_TRUE != LML_VirtualPageWrite(&DstParam)){
  247. LOGICCTL_ERR("move merge : write err\n");
  248. return NAND_OP_FALSE;
  249. }
  250. }
  251. if (NAND_OP_TRUE != PHY_SynchBank(DstParam.BankNum, SYNC_BANK_MODE))
  252. {
  253. struct __SuperPhyBlkType_t SubBlk;
  254. if (NAND_OP_TRUE != LML_BadBlkManage(&FreeBlk,CUR_MAP_ZONE,LastUsedPage,&SubBlk))
  255. {
  256. LOGICCTL_ERR("move merge : bad block manage err after copy back\n");
  257. return NAND_OP_FALSE;
  258. }
  259. FreeBlk = SubBlk;
  260. SuperPage -= 1;
  261. }
  262. PMM_SetCurMapPage(SuperPage,DstPage);
  263. LastUsedPage = DstPage;
  264. DstPage++;
  265. }
  266. }
  267. #endif
  268. /*erase log block*/
  269. if(NAND_OP_TRUE != LML_VirtualBlkErase(CUR_MAP_ZONE, LogBlk.PhyBlk.PhyBlkNum))
  270. {
  271. if(NAND_OP_TRUE != LML_BadBlkManage(&LogBlk.PhyBlk,CUR_MAP_ZONE,0,NULL))
  272. {
  273. LOGICCTL_ERR("move merge : bad block manage err after erase log block\n");
  274. return NAND_OP_FALSE;
  275. }
  276. }
  277. /*move erased log block to free block*/
  278. if(LogBlk.PhyBlk.BlkEraseCnt < 0xffff)
  279. {
  280. LogBlk.PhyBlk.BlkEraseCnt ++;
  281. }
  282. BMM_SetFreeBlk(&LogBlk.PhyBlk);
  283. /*move free block to log block*/
  284. LogBlk.PhyBlk = FreeBlk;
  285. LogBlk.LastUsedPage = LastUsedPage;
  286. BMM_SetLogBlk(nlogical, &LogBlk);
  287. return NAND_OP_TRUE;
  288. }
  289. /*!
  290. *
  291. * \par Description:
  292. * This function copy valuable data from log block or dat block to free block, change free to data ,change
  293. * data and log to free.
  294. *
  295. * \param [in] LogNum,serial number within log block space
  296. * \return sucess or failed.
  297. * \note this function was called when log block is not suit for swap or move.
  298. **/
  299. __s32 _free2data_simple_merge(__u32 nlogical)
  300. {
  301. __u8 InData;
  302. __u16 SuperPage;
  303. __u16 SrcPage,DstPage;
  304. __u32 SrcBlk,DstBlk;
  305. struct __SuperPhyBlkType_t DataBlk;
  306. struct __SuperPhyBlkType_t FreeBlk;
  307. struct __LogBlkType_t LogBlk;
  308. struct __PhysicOpPara_t SrcParam,DstParam;
  309. /*init block info*/
  310. BMM_GetDataBlk(nlogical,&DataBlk);
  311. if (NAND_OP_TRUE != BMM_GetFreeBlk(LOWEST_EC_TYPE, &FreeBlk))
  312. return NAND_OP_FALSE;
  313. BMM_GetLogBlk(nlogical,&LogBlk);
  314. /*copy data from data block or log block to free block*/
  315. for (SuperPage = 0; SuperPage < PAGE_CNT_OF_LOGIC_BLK; SuperPage++)
  316. {
  317. /*set source address and destination address*/
  318. DstPage = SuperPage;
  319. DstBlk = FreeBlk.PhyBlkNum;
  320. SrcPage = PMM_GetCurMapPage(SuperPage);
  321. InData = (SrcPage == 0xffff)?1 : 0;
  322. SrcBlk = InData?DataBlk.PhyBlkNum : LogBlk.PhyBlk.PhyBlkNum;
  323. SrcPage = InData?SuperPage:SrcPage;
  324. LML_CalculatePhyOpPar(&SrcParam, CUR_MAP_ZONE,SrcBlk, SrcPage);
  325. LML_CalculatePhyOpPar(&DstParam, CUR_MAP_ZONE,DstBlk, DstPage);
  326. if (DstPage == 0)
  327. {
  328. __u8 SeqPlus;
  329. //SeqPlus = InData?1:0;
  330. SeqPlus = InData?2:1;
  331. if(NAND_OP_FALSE == _copy_page0(SrcBlk, SrcPage, DstBlk,SeqPlus))
  332. {
  333. LOGICCTL_ERR("simple_merge : copy page 0 err\n");
  334. return NAND_OP_FALSE;
  335. }
  336. }
  337. else
  338. {
  339. if(NAND_OP_TRUE != PHY_PageCopyback(&SrcParam,&DstParam))
  340. {
  341. LOGICCTL_ERR("simple merge : copy back err\n");
  342. return NAND_OP_FALSE;
  343. }
  344. }
  345. if(NAND_OP_TRUE != PHY_SynchBank(DstParam.BankNum, SYNC_BANK_MODE))
  346. {
  347. struct __SuperPhyBlkType_t SubBlk;
  348. if(NAND_OP_TRUE != LML_BadBlkManage(&FreeBlk,CUR_MAP_ZONE,DstPage, &SubBlk))
  349. {
  350. LOGICCTL_ERR("simgple merge : bad block manage err after copy back\n");
  351. return NAND_OP_FALSE;
  352. }
  353. FreeBlk = SubBlk;
  354. SuperPage -= 1;
  355. }
  356. }
  357. /*move free block to data block*/
  358. BMM_SetDataBlk(nlogical, &FreeBlk);
  359. /*move erased data block to free block*/
  360. if ( NAND_OP_TRUE != LML_VirtualBlkErase(CUR_MAP_ZONE, DataBlk.PhyBlkNum)){
  361. if (NAND_OP_TRUE != LML_BadBlkManage(&DataBlk,CUR_MAP_ZONE,0,NULL)){
  362. LOGICCTL_ERR("swap merge : bad block manage err erase data block\n");
  363. return NAND_OP_FALSE;
  364. }
  365. }
  366. /*move erased data block to free block*/
  367. if (DataBlk.BlkEraseCnt < 0xffff)
  368. DataBlk.BlkEraseCnt ++;
  369. BMM_SetFreeBlk(&DataBlk);
  370. /*move erased log block to free block*/
  371. if ( NAND_OP_TRUE != LML_VirtualBlkErase(CUR_MAP_ZONE, LogBlk.PhyBlk.PhyBlkNum)){
  372. if (NAND_OP_TRUE != LML_BadBlkManage(&LogBlk.PhyBlk,CUR_MAP_ZONE,0,NULL)){
  373. LOGICCTL_ERR("move merge : bad block manage err after erase log block\n");
  374. return NAND_OP_FALSE;
  375. }
  376. }
  377. if (LogBlk.PhyBlk.BlkEraseCnt < 0xffff)
  378. LogBlk.PhyBlk.BlkEraseCnt ++;
  379. BMM_SetFreeBlk(&LogBlk.PhyBlk);
  380. MEMSET(&LogBlk, 0xff, sizeof(struct __LogBlkType_t));
  381. BMM_SetLogBlk(nlogical, &LogBlk);
  382. /*clear page map table*/
  383. PMM_ClearCurMapTbl();
  384. return NAND_OP_TRUE;
  385. }
  386. void _get_page_map_tbl_info(__u32 nlogical,__u8 *InOrder, __u16 *nValidPage)
  387. {
  388. __u16 LastUsedPage,PhysicPage;
  389. __u32 i;
  390. struct __LogBlkType_t LogBlk;
  391. *InOrder = 1;
  392. *nValidPage = 0;
  393. BMM_GetLogBlk(nlogical, &LogBlk);
  394. LastUsedPage = LogBlk.LastUsedPage;
  395. for (i = 0; i < PAGE_CNT_OF_SUPER_BLK; i++)
  396. {
  397. PhysicPage = PMM_GetCurMapPage(i);
  398. if (PhysicPage != 0xffff){
  399. *nValidPage = *nValidPage + 1;
  400. if (PhysicPage != i)
  401. *InOrder = 0;
  402. }
  403. }
  404. if (*nValidPage < LastUsedPage + 1)
  405. *InOrder = 0;
  406. }
  407. /*
  408. ************************************************************************************************************************
  409. * NAND FLASH LOGIC MANAGE LAYER MERGE LOG BLOCK
  410. *
  411. *Description: Merge the log block whoes mapping table is active.
  412. *
  413. *Arguments : nMode the type of the merge;
  414. * = 0 normal merge, the log block table is not full;
  415. * = 1 special merge, the log block table is full.
  416. *
  417. *Return : merge result;
  418. * = 0 merge log successful;
  419. * = -1 do bad block manage failed.
  420. ************************************************************************************************************************
  421. */
  422. __s32 LML_MergeLogBlk(__u32 nMode, __u32 nlogical)
  423. {
  424. __u8 InOrder;
  425. __u16 nValidPage;
  426. _get_page_map_tbl_info(nlogical,&InOrder,&nValidPage);
  427. if (InOrder)
  428. return (_log2data_swap_merge(nlogical));
  429. else{
  430. if ( (nMode == SPECIAL_MERGE_MODE) && (nValidPage < PAGE_CNT_OF_SUPER_BLK/(INTERLEAVE_BANK_CNT+1)))
  431. return (_free2log_move_merge(nlogical));
  432. else
  433. return (_free2data_simple_merge(nlogical));
  434. }
  435. }