nandemul2k.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714
  1. /*
  2. * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
  3. *
  4. * Copyright (C) 2002-2007 Aleph One Ltd.
  5. * for Toby Churchill Ltd and Brightstar Engineering
  6. *
  7. * Created by Charles Manning <charles@aleph1.co.uk>
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License version 2 as
  11. * published by the Free Software Foundation.
  12. */
  13. /*
  14. * This version hacked for emulating 2kpage NAND for YAFFS2 testing.
  15. */
  16. #include <linux/config.h>
  17. #include <linux/kernel.h>
  18. #include <linux/module.h>
  19. #include <linux/version.h>
  20. #include <linux/slab.h>
  21. #include <linux/init.h>
  22. #include <linux/list.h>
  23. #include <linux/fs.h>
  24. #include <linux/proc_fs.h>
  25. #include <linux/pagemap.h>
  26. #include <linux/mtd/mtd.h>
  27. #include <linux/interrupt.h>
  28. #include <linux/string.h>
  29. #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
  30. #include <linux/locks.h>
  31. #endif
  32. #include <asm/uaccess.h>
  33. #include <linux/mtd/mtd.h>
  34. #include <linux/mtd/partitions.h>
  35. #include <linux/mtd/nand.h>
  36. #include "../yaffs_nandemul2k.h"
  37. #define ALLOCATE(x) kmalloc(x,GFP_KERNEL)
  38. #define FREE(x) kfree(x)
  39. #define NAND_SHIFT (11) // Shifter for 2k
  40. #define PAGE_DATA_SIZE (1 << NAND_SHIFT)
  41. #define PAGE_SPARE_SIZE (64)
  42. #define BLK_SHIFT 6
  43. #define PAGES_PER_BLOCK (1 << BLK_SHIFT) // = 64
  44. #define EM_SIZE_IN_MEG 4
  45. #define EM_SIZE_IN_BYTES (EM_SIZE_IN_MEG * (1<<20))
  46. #define PAGE_TOTAL_SIZE (PAGE_DATA_SIZE+PAGE_SPARE_SIZE)
  47. #define BLOCK_TOTAL_SIZE (PAGES_PER_BLOCK * PAGE_TOTAL_SIZE)
  48. #define BLOCKS_PER_MEG ((1<<20)/(PAGES_PER_BLOCK * PAGE_DATA_SIZE))
  49. static struct mtd_info nandemul2k_mtd;
  50. typedef struct
  51. {
  52. __u8 data[PAGE_TOTAL_SIZE]; // Data + spare
  53. int empty; // is this empty?
  54. } nandemul_Page;
  55. typedef struct
  56. {
  57. nandemul_Page *page[PAGES_PER_BLOCK];
  58. int damaged;
  59. } nandemul_Block;
  60. typedef struct
  61. {
  62. nandemul_Block**block;
  63. int nBlocks;
  64. } nandemul_Device;
  65. static nandemul_Device ned;
  66. static int sizeInMB = EM_SIZE_IN_MEG;
  67. static void nandemul_yield(int n)
  68. {
  69. #ifdef __KERNEL__
  70. if(n > 0) schedule_timeout(n);
  71. #endif
  72. }
  73. static void nandemul2k_Read(void *buffer, int page, int start, int nBytes)
  74. {
  75. int pg = page%PAGES_PER_BLOCK;
  76. int blk = page/PAGES_PER_BLOCK;
  77. if(buffer && nBytes > 0)
  78. {
  79. memcpy(buffer,&ned.block[blk]->page[pg]->data[start],nBytes);
  80. }
  81. }
  82. static void nandemul2k_Program(const void *buffer, int page, int start, int nBytes)
  83. {
  84. int pg = page%PAGES_PER_BLOCK;
  85. int blk = page/PAGES_PER_BLOCK;
  86. __u8 *p;
  87. __u8 *b = (__u8 *)buffer;
  88. p = &ned.block[blk]->page[pg]->data[start];
  89. while(buffer && nBytes>0)
  90. {
  91. *p = *p & *b;
  92. p++;
  93. b++;
  94. nBytes--;
  95. }
  96. }
  97. static void nandemul2k_DoErase(int blockNumber)
  98. {
  99. int i;
  100. nandemul_Block *blk;
  101. if(blockNumber < 0 || blockNumber >= ned.nBlocks)
  102. {
  103. return;
  104. }
  105. blk = ned.block[blockNumber];
  106. for(i = 0; i < PAGES_PER_BLOCK; i++)
  107. {
  108. memset(blk->page[i],0xff,sizeof(nandemul_Page));
  109. blk->page[i]->empty = 1;
  110. }
  111. nandemul_yield(2);
  112. }
  113. static int nandemul2k_CalcNBlocks(void)
  114. {
  115. return EM_SIZE_IN_MEG * BLOCKS_PER_MEG;
  116. }
  117. static int CheckInit(void)
  118. {
  119. static int initialised = 0;
  120. int i,j;
  121. int fail = 0;
  122. int nBlocks;
  123. int nAllocated = 0;
  124. if(initialised)
  125. {
  126. return 0;
  127. }
  128. ned.nBlocks = nBlocks = nandemul2k_CalcNBlocks();
  129. ned.block = ALLOCATE(sizeof(nandemul_Block*) * nBlocks );
  130. if(!ned.block) return ENOMEM;
  131. for(i=fail=0; i <nBlocks; i++)
  132. {
  133. nandemul_Block *blk;
  134. if(!(blk = ned.block[i] = ALLOCATE(sizeof(nandemul_Block))))
  135. {
  136. fail = 1;
  137. }
  138. else
  139. {
  140. for(j = 0; j < PAGES_PER_BLOCK; j++)
  141. {
  142. if((blk->page[j] = ALLOCATE(sizeof(nandemul_Page))) == 0)
  143. {
  144. fail = 1;
  145. }
  146. }
  147. nandemul2k_DoErase(i);
  148. ned.block[i]->damaged = 0;
  149. nAllocated++;
  150. }
  151. }
  152. if(fail)
  153. {
  154. //Todo thump pages
  155. for(i = 0; i < nAllocated; i++)
  156. {
  157. FREE(ned.block[i]);
  158. }
  159. FREE(ned.block);
  160. return ENOMEM;
  161. }
  162. ned.nBlocks = nBlocks;
  163. initialised = 1;
  164. return 1;
  165. }
  166. static void nandemul2k_CleanUp(void)
  167. {
  168. int i,j;
  169. for(i = 0; i < ned.nBlocks; i++)
  170. {
  171. for(j = 0; j < PAGES_PER_BLOCK; j++)
  172. {
  173. FREE(ned.block[i]->page[j]);
  174. }
  175. FREE(ned.block[i]);
  176. }
  177. FREE(ned.block);
  178. ned.block = 0;
  179. }
  180. int nandemul2k_GetBytesPerChunk(void) { return PAGE_DATA_SIZE;}
  181. int nandemul2k_GetChunksPerBlock(void) { return PAGES_PER_BLOCK; }
  182. int nandemul2k_GetNumberOfBlocks(void) {return nandemul2k_CalcNBlocks();}
  183. static int nandemul2k_ReadId(__u8 *vendorId, __u8 *deviceId)
  184. {
  185. *vendorId = 'Y';
  186. *deviceId = '2';
  187. return 1;
  188. }
  189. static int nandemul2k_ReadStatus(__u8 *status)
  190. {
  191. *status = 0;
  192. return 1;
  193. }
  194. #ifdef CONFIG_MTD_NAND_ECC
  195. #include <linux/mtd/nand_ecc.h>
  196. #endif
  197. /*
  198. * NAND low-level MTD interface functions
  199. */
  200. static int nand_read (struct mtd_info *mtd, loff_t from, size_t len,
  201. size_t *retlen, u_char *buf);
  202. static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
  203. size_t *retlen, u_char *buf, u_char *oob_buf, struct nand_oobinfo *dummy);
  204. static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
  205. size_t *retlen, u_char *buf);
  206. static int nand_write (struct mtd_info *mtd, loff_t to, size_t len,
  207. size_t *retlen, const u_char *buf);
  208. static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
  209. size_t *retlen, const u_char *buf,
  210. u_char *oob_buf, struct nand_oobinfo *dummy);
  211. static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
  212. size_t *retlen, const u_char *buf);
  213. #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,7))
  214. static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs,
  215. unsigned long count, loff_t to, size_t *retlen);
  216. #else
  217. static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs,
  218. unsigned long count, loff_t to, size_t *retlen);
  219. #endif
  220. static int nand_erase (struct mtd_info *mtd, struct erase_info *instr);
  221. static void nand_sync (struct mtd_info *mtd);
  222. /*
  223. * NAND read
  224. */
  225. static int nand_read (struct mtd_info *mtd, loff_t from, size_t len,
  226. size_t *retlen, u_char *buf)
  227. {
  228. return nand_read_ecc (mtd, from, len, retlen, buf, NULL,NULL);
  229. }
  230. /*
  231. * NAND read with ECC
  232. */
  233. static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
  234. size_t *retlen, u_char *buf, u_char *oob_buf,struct nand_oobinfo *oobsel)
  235. {
  236. int start, page;
  237. int n = len;
  238. int nToCopy;
  239. /* Do not allow reads past end of device */
  240. if ((from + len) > mtd->size) {
  241. *retlen = 0;
  242. return -EINVAL;
  243. }
  244. /* Initialize return value */
  245. *retlen = 0;
  246. while(n > 0)
  247. {
  248. /* First we calculate the starting page */
  249. page = from >> NAND_SHIFT;
  250. /* Get raw starting column */
  251. start = from & (mtd->oobblock-1);
  252. // OK now check for the curveball where the start and end are in
  253. // the same page
  254. if((start + n) < mtd->oobblock)
  255. {
  256. nToCopy = n;
  257. }
  258. else
  259. {
  260. nToCopy = mtd->oobblock - start;
  261. }
  262. nandemul2k_Read(buf, page, start, nToCopy);
  263. nandemul2k_Read(oob_buf,page,PAGE_DATA_SIZE,PAGE_SPARE_SIZE);
  264. n -= nToCopy;
  265. from += nToCopy;
  266. buf += nToCopy;
  267. if(oob_buf) oob_buf += PAGE_SPARE_SIZE;
  268. *retlen += nToCopy;
  269. }
  270. return 0;
  271. }
  272. /*
  273. * NAND read out-of-band
  274. */
  275. static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
  276. size_t *retlen, u_char *buf)
  277. {
  278. int col, page;
  279. T(0,("nand_read_oob: from = 0x%08x, buf = 0x%08x, len = %i\n", (unsigned int) from, (unsigned int) buf,
  280. (int) len));
  281. /* Shift to get page */
  282. page = ((int) from) >> NAND_SHIFT;
  283. /* Mask to get column */
  284. col = from & 0x0f;
  285. /* Initialize return length value */
  286. *retlen = 0;
  287. /* Do not allow reads past end of device */
  288. if ((from + len) > mtd->size) {
  289. T(0,
  290. ("nand_read_oob: Attempt read beyond end of device\n"));
  291. *retlen = 0;
  292. return -EINVAL;
  293. }
  294. nandemul2k_Read(buf,page,PAGE_DATA_SIZE + col,len);
  295. /* Return happy */
  296. *retlen = len;
  297. return 0;
  298. }
  299. /*
  300. * NAND write
  301. */
  302. static int nand_write (struct mtd_info *mtd, loff_t to, size_t len,
  303. size_t *retlen, const u_char *buf)
  304. {
  305. return nand_write_ecc (mtd, to, len, retlen, buf, NULL,NULL);
  306. }
  307. /*
  308. * NAND write with ECC
  309. */
  310. static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
  311. size_t *retlen, const u_char *buf,
  312. u_char *oob_buf, struct nand_oobinfo *dummy)
  313. {
  314. int start, page;
  315. int n = len;
  316. int nToCopy;
  317. /* Do not allow reads past end of device */
  318. if ((to + len) > mtd->size) {
  319. *retlen = 0;
  320. return -EINVAL;
  321. }
  322. /* Initialize return value */
  323. *retlen = 0;
  324. while(n > 0)
  325. {
  326. /* First we calculate the starting page */
  327. page = to >> NAND_SHIFT;
  328. /* Get raw starting column */
  329. start = to & (mtd->oobblock - 1);
  330. // OK now check for the curveball where the start and end are in
  331. // the same page
  332. if((start + n) < mtd->oobblock)
  333. {
  334. nToCopy = n;
  335. }
  336. else
  337. {
  338. nToCopy = mtd->oobblock - start;
  339. }
  340. nandemul2k_Program(buf, page, start, nToCopy);
  341. nandemul2k_Program(oob_buf, page, PAGE_DATA_SIZE, PAGE_SPARE_SIZE);
  342. n -= nToCopy;
  343. to += nToCopy;
  344. buf += nToCopy;
  345. if(oob_buf) oob_buf += PAGE_SPARE_SIZE;
  346. *retlen += nToCopy;
  347. }
  348. return 0;
  349. }
  350. /*
  351. * NAND write out-of-band
  352. */
  353. static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
  354. size_t *retlen, const u_char *buf)
  355. {
  356. int col, page;
  357. T(0,(
  358. "nand_read_oob: to = 0x%08x, len = %i\n", (unsigned int) to,
  359. (int) len));
  360. /* Shift to get page */
  361. page = ((int) to) >> NAND_SHIFT;
  362. /* Mask to get column */
  363. col = to & 0x0f;
  364. /* Initialize return length value */
  365. *retlen = 0;
  366. /* Do not allow reads past end of device */
  367. if ((to + len) > mtd->size) {
  368. T(0,(
  369. "nand_read_oob: Attempt read beyond end of device\n"));
  370. *retlen = 0;
  371. return -EINVAL;
  372. }
  373. nandemul2k_Program(buf,page,512 + col,len);
  374. /* Return happy */
  375. *retlen = len;
  376. return 0;
  377. }
  378. /*
  379. * NAND write with iovec
  380. */
  381. #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,7))
  382. static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs,
  383. unsigned long count, loff_t to, size_t *retlen)
  384. #else
  385. static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs,
  386. unsigned long count, loff_t to, size_t *retlen)
  387. #endif
  388. {
  389. return -EINVAL;
  390. }
  391. /*
  392. * NAND erase a block
  393. */
  394. static int nand_erase (struct mtd_info *mtd, struct erase_info *instr)
  395. {
  396. int i, nBlocks,block;
  397. T(0,(
  398. "nand_erase: start = 0x%08x, len = %i\n",
  399. (unsigned int) instr->addr, (unsigned int) instr->len));
  400. /* Start address must align on block boundary */
  401. if (instr->addr & (mtd->erasesize - 1)) {
  402. T(0,(
  403. "nand_erase: Unaligned address\n"));
  404. return -EINVAL;
  405. }
  406. /* Length must align on block boundary */
  407. if (instr->len & (mtd->erasesize - 1)) {
  408. T(0,(
  409. "nand_erase: Length not block aligned\n"));
  410. return -EINVAL;
  411. }
  412. /* Do not allow erase past end of device */
  413. if ((instr->len + instr->addr) > mtd->size) {
  414. T(0,(
  415. "nand_erase: Erase past end of device\n"));
  416. return -EINVAL;
  417. }
  418. nBlocks = instr->len >> (NAND_SHIFT + BLK_SHIFT);
  419. block = instr->addr >> (NAND_SHIFT + BLK_SHIFT);
  420. for(i = 0; i < nBlocks; i++)
  421. {
  422. nandemul2k_DoErase(block);
  423. block++;
  424. }
  425. instr->state = MTD_ERASE_DONE;  * change state to ERASE_DONE */
  426. instr->callback(instr);  * wake up */
  427. return 0;
  428. }
  429. static int nand_block_isbad(struct mtd_info *mtd, loff_t ofs)
  430. {
  431. return 0;
  432. }
  433. static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
  434. {
  435. return 0;
  436. }
  437. /*
  438. * NAND sync
  439. */
  440. static void nand_sync (struct mtd_info *mtd)
  441. {
  442. T(0,("nand_sync: called\n"));
  443. }
  444. /*
  445. * Scan for the NAND device
  446. */
  447. static int nandemul2k_scan (struct mtd_info *mtd,int nchips)
  448. {
  449. mtd->oobblock = PAGE_DATA_SIZE;
  450. mtd->oobsize = PAGE_SPARE_SIZE;
  451. mtd->erasesize = PAGE_DATA_SIZE * PAGES_PER_BLOCK;
  452. mtd->size = sizeInMB * 1024*1024;
  453. /* Fill in remaining MTD driver data */
  454. mtd->type = MTD_NANDFLASH;
  455. mtd->flags = MTD_CAP_NANDFLASH;
  456. mtd->owner = THIS_MODULE;
  457. mtd->ecctype = MTD_ECC_NONE;
  458. mtd->erase = nand_erase;
  459. mtd->point = NULL;
  460. mtd->unpoint = NULL;
  461. mtd->read = nand_read;
  462. mtd->write = nand_write;
  463. mtd->read_ecc = nand_read_ecc;
  464. mtd->write_ecc = nand_write_ecc;
  465. mtd->read_oob = nand_read_oob;
  466. mtd->write_oob = nand_write_oob;
  467. mtd->block_isbad = nand_block_isbad;
  468. mtd->block_markbad = nand_block_markbad;
  469. mtd->readv = NULL;
  470. mtd->writev = nand_writev;
  471. mtd->sync = nand_sync;
  472. mtd->lock = NULL;
  473. mtd->unlock = NULL;
  474. mtd->suspend = NULL;
  475. mtd->resume = NULL;
  476. mtd->name = "NANDemul2k";
  477. /* Return happy */
  478. return 0;
  479. }
  480. #if 0
  481. #ifdef MODULE
  482. MODULE_PARM(sizeInMB, "i");
  483. __setup("sizeInMB=",sizeInMB);
  484. #endif
  485. #endif
  486. /*
  487. * Define partitions for flash devices
  488. */
  489. static struct mtd_partition nandemul2k_partition[] =
  490. {
  491. { .name = "NANDemul partition 1",
  492. .offset = 0,
  493. .size = 0 },
  494. };
  495. static int nPartitions = sizeof(nandemul2k_partition)/sizeof(nandemul2k_partition[0]);
  496. /*
  497. * Main initialization routine
  498. */
  499. int __init nandemul2k_init (void)
  500. {
  501. // Do the nand init
  502. CheckInit();
  503. nandemul2k_scan(&nandemul2k_mtd,1);
  504. // Build the partition table
  505. nandemul2k_partition[0].size = sizeInMB * 1024 * 1024;
  506. // Register the partition
  507. add_mtd_partitions(&nandemul2k_mtd,nandemul2k_partition,nPartitions);
  508. return 0;
  509. }
  510. module_init(nandemul2k_init);
  511. /*
  512. * Clean up routine
  513. */
  514. #ifdef MODULE
  515. static void __exit nandemul2k_cleanup (void)
  516. {
  517. nandemul2k_CleanUp();
  518. /* Unregister partitions */
  519. del_mtd_partitions(&nandemul2k_mtd);
  520. /* Unregister the device */
  521. del_mtd_device (&nandemul2k_mtd);
  522. }
  523. module_exit(nandemul2k_cleanup);
  524. #endif
  525. MODULE_LICENSE("GPL");
  526. MODULE_AUTHOR("Charles Manning <manningc@aleph1.co.uk>");
  527. MODULE_DESCRIPTION("2k Page/128k Block NAND emulated in RAM");