static int mtd_open(struct inode *inode, struct file *file) { int minor = iminor(inode); int devnum = minor >> 1; struct mtd_info *mtd; struct mtd_file_info *mfi; DEBUG(MTD_DEBUG_LEVEL0, "MTD_open\n"); if (devnum >= MAX_MTD_DEVICES) return -ENODEV; /* You can't open the RO devices RW */ if ((file->f_mode & 2) && (minor & 1)) return -EACCES; mtd = get_mtd_device(NULL, devnum); if (IS_ERR(mtd)) return PTR_ERR(mtd); if (MTD_ABSENT == mtd->type) { put_mtd_device(mtd); return -ENODEV; } /* You can't open it RW if it's not a writeable device */ if ((file->f_mode & 2) && !(mtd->flags & MTD_WRITEABLE)) { put_mtd_device(mtd); return -EACCES; } mfi = kzalloc(sizeof(*mfi), GFP_KERNEL); if (!mfi) { put_mtd_device(mtd); return -ENOMEM; } mfi->mtd = mtd; file->private_data = mfi; return 0; } /* mtd_open */
static int __init mtd_unlocker_init(void) { struct mtd_info *mtd; int i; for (i = 0; true; ++i) { mtd = get_mtd_device(NULL, i); if (!IS_ERR(mtd) && !(mtd->flags & MTD_WRITEABLE)) { printk(KERN_INFO "mtd-unlocker: unlocking mtd%d\n", i); mtd->flags |= MTD_WRITEABLE; put_mtd_device(mtd); } else { break; } } printk(KERN_INFO "mtd-unlocker: %d device(s) unlocked\n", i); return 0; }
int ar7240_gpio_open (struct inode *inode, struct file *filp) { int minor = iminor(inode); int devnum = minor; //>> 1; struct mtd_info *mtd; if ((filp->f_mode & 2) && (minor & 1)) { printk("You can't open the RO devices RW!\n"); return -EACCES; } mtd = get_mtd_device(NULL, devnum); if (!mtd) { printk("Can not open mtd!\n"); return -ENODEV; } filp->private_data = mtd; return 0; }
int nettel_eraseconfig(void) { struct mtd_info *mtd; DECLARE_WAITQUEUE(wait, current); wait_queue_head_t wait_q; int ret; init_waitqueue_head(&wait_q); mtd = get_mtd_device(NULL, 2); if (mtd) { nettel_erase.mtd = mtd; nettel_erase.callback = nettel_erasecallback; nettel_erase.callback = NULL; nettel_erase.addr = 0; nettel_erase.len = mtd->size; nettel_erase.priv = (u_long) &wait_q; nettel_erase.priv = 0; set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&wait_q, &wait); ret = mtd->erase(mtd, &nettel_erase); if (ret) { set_current_state(TASK_RUNNING); remove_wait_queue(&wait_q, &wait); put_mtd_device(mtd); return(ret); } schedule(); /* Wait for erase to finish. */ remove_wait_queue(&wait_q, &wait); put_mtd_device(mtd); } return(0); }
static int mtd_open(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); int devnum = minor >> 1; struct mtd_info *mtd; DEBUG(MTD_DEBUG_LEVEL0, "MTD_open\n"); if (devnum >= MAX_MTD_DEVICES) return -ENODEV; /* You can't open the RO devices RW */ if ((file->f_mode & 2) && (minor & 1)) return -EACCES; mtd = get_mtd_device(NULL, devnum); if (!mtd) return -ENODEV; if (MTD_ABSENT == mtd->type) { put_mtd_device(mtd); return -ENODEV; } MOD_INC_USE_COUNT; file->private_data = mtd; /* You can't open it RW if it's not a writeable device */ if ((file->f_mode & 2) && !(mtd->flags & MTD_WRITEABLE)) { put_mtd_device(mtd); MOD_DEC_USE_COUNT; return -EACCES; } return 0; } /* mtd_open */
static int __init mtd_subpagetest_init(void) { int err = 0; uint32_t i; uint64_t tmp; printk(KERN_INFO "\n"); printk(KERN_INFO "=================================================\n"); printk(PRINT_PREF "MTD device: %d\n", dev); mtd = get_mtd_device(NULL, dev); if (IS_ERR(mtd)) { err = PTR_ERR(mtd); printk(PRINT_PREF "error: cannot get MTD device\n"); return err; } if (mtd->type != MTD_NANDFLASH) { printk(PRINT_PREF "this test requires NAND flash\n"); goto out; } subpgsize = mtd->writesize >> mtd->subpage_sft; <<<<<<< HEAD
static int __init mtd_subpagetest_init(void) { int err = 0; uint32_t i; uint64_t tmp; printk(KERN_INFO "\n"); printk(KERN_INFO "=================================================\n"); if (dev < 0) { pr_info("Please specify a valid mtd-device via module parameter\n"); pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n"); return -EINVAL; } pr_info("MTD device: %d\n", dev); mtd = get_mtd_device(NULL, dev); if (IS_ERR(mtd)) { err = PTR_ERR(mtd); pr_err("error: cannot get MTD device\n"); return err; } if (mtd->type != MTD_NANDFLASH) { pr_info("this test requires NAND flash\n"); goto out; } subpgsize = mtd->writesize >> mtd->subpage_sft; tmp = mtd->size; do_div(tmp, mtd->erasesize); ebcnt = tmp; pgcnt = mtd->erasesize / mtd->writesize; pr_info("MTD device size %llu, eraseblock size %u, " "page size %u, subpage size %u, count of eraseblocks %u, " "pages per eraseblock %u, OOB size %u\n", (unsigned long long)mtd->size, mtd->erasesize, mtd->writesize, subpgsize, ebcnt, pgcnt, mtd->oobsize); err = -ENOMEM; bufsize = subpgsize * 32; writebuf = kmalloc(bufsize, GFP_KERNEL); if (!writebuf) goto out; readbuf = kmalloc(bufsize, GFP_KERNEL); if (!readbuf) goto out; bbt = kzalloc(ebcnt, GFP_KERNEL); if (!bbt) goto out; err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt); if (err) goto out; err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); if (err) goto out; pr_info("writing whole device\n"); prandom_seed_state(&rnd_state, 1); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; err = write_eraseblock(i); if (unlikely(err)) goto out; if (i % 256 == 0) pr_info("written up to eraseblock %u\n", i); cond_resched(); } pr_info("written %u eraseblocks\n", i); prandom_seed_state(&rnd_state, 1); pr_info("verifying all eraseblocks\n"); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; err = verify_eraseblock(i); if (unlikely(err)) goto out; if (i % 256 == 0) pr_info("verified up to eraseblock %u\n", i); cond_resched(); } pr_info("verified %u eraseblocks\n", i); err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); if (err) goto out; err = verify_all_eraseblocks_ff(); if (err) goto out; /* Write all eraseblocks */ prandom_seed_state(&rnd_state, 3); pr_info("writing whole device\n"); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; err = write_eraseblock2(i); if (unlikely(err)) goto out; if (i % 256 == 0) pr_info("written up to eraseblock %u\n", i); cond_resched(); } pr_info("written %u eraseblocks\n", i); /* Check all eraseblocks */ prandom_seed_state(&rnd_state, 3); pr_info("verifying all eraseblocks\n"); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; err = verify_eraseblock2(i); if (unlikely(err)) goto out; if (i % 256 == 0) pr_info("verified up to eraseblock %u\n", i); cond_resched(); } pr_info("verified %u eraseblocks\n", i); err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); if (err) goto out; err = verify_all_eraseblocks_ff(); if (err) goto out; pr_info("finished with %d errors\n", errcnt); out: kfree(bbt); kfree(readbuf); kfree(writebuf); put_mtd_device(mtd); if (err) pr_info("error %d occurred\n", err); printk(KERN_INFO "=================================================\n"); return err; }
static int cramfs_fill_super(struct super_block *sb, void *data, int silent) { int i; struct cramfs_super super; unsigned long root_offset; struct cramfs_sb_info *sbi; struct inode *root; sb->s_flags |= MS_RDONLY; sbi = kzalloc(sizeof(struct cramfs_sb_info), GFP_KERNEL); if (!sbi) return -ENOMEM; sb->s_fs_info = sbi; cramfs_read = cramfs_read_comm; if (MAJOR(sb->s_dev) == MTD_BLOCK_MAJOR) { struct mtd_info *mtd; int blocks, *block_map; mtd = get_mtd_device(NULL, MINOR(sb->s_dev)); if (!mtd) goto not_mtdblock; if (mtd->type != MTD_NANDFLASH) goto not_mtdblock; cramfs_read = cramfs_read_nand; sbi->mtd = mtd; blocks = mtd->size / mtd->erasesize; block_map = kmalloc(blocks * sizeof(int), GFP_KERNEL); for (i = 0; i < blocks; i++) { block_map[i] = -1; } sbi->block_map = block_map; sbi->nblock = blocks; } not_mtdblock: /* Invalidate the read buffers on mount: think disk change.. */ mutex_lock(&read_mutex); for (i = 0; i < READ_BUFFERS; i++) buffer_blocknr[i] = -1; /* Read the first block and get the superblock from it */ memcpy(&super, cramfs_read(sb, 0, sizeof(super)), sizeof(super)); mutex_unlock(&read_mutex); /* Do sanity checks on the superblock */ if (super.magic != CRAMFS_MAGIC) { /* check for wrong endianess */ if (super.magic == CRAMFS_MAGIC_WEND) { if (!silent) printk(KERN_ERR "cramfs: wrong endianess\n"); goto out; } /* check at 512 byte offset */ mutex_lock(&read_mutex); memcpy(&super, cramfs_read(sb, 512, sizeof(super)), sizeof(super)); mutex_unlock(&read_mutex); if (super.magic != CRAMFS_MAGIC) { if (super.magic == CRAMFS_MAGIC_WEND && !silent) printk(KERN_ERR "cramfs: wrong endianess\n"); else if (!silent) printk(KERN_ERR "cramfs: wrong magic\n"); goto out; } } /* get feature flags first */ if (super.flags & ~CRAMFS_SUPPORTED_FLAGS) { printk(KERN_ERR "cramfs: unsupported filesystem features\n"); goto out; } /* Check that the root inode is in a sane state */ if (!S_ISDIR(super.root.mode)) { printk(KERN_ERR "cramfs: root is not a directory\n"); goto out; } root_offset = super.root.offset << 2; if (super.flags & CRAMFS_FLAG_FSID_VERSION_2) { sbi->size=super.size; sbi->blocks=super.fsid.blocks; sbi->files=super.fsid.files; } else { sbi->size=1<<28; sbi->blocks=0; sbi->files=0; } sbi->magic=super.magic; sbi->flags=super.flags; if (root_offset == 0) printk(KERN_INFO "cramfs: empty filesystem"); else if (!(super.flags & CRAMFS_FLAG_SHIFTED_ROOT_OFFSET) && ((root_offset != sizeof(struct cramfs_super)) && (root_offset != 512 + sizeof(struct cramfs_super)))) { printk(KERN_ERR "cramfs: bad root offset %lu\n", root_offset); goto out; } /* Set it all up.. */ sb->s_op = &cramfs_ops; root = get_cramfs_inode(sb, &super.root); if (!root) goto out; sb->s_root = d_alloc_root(root); if (!sb->s_root) { iput(root); goto out; } return 0; out: kfree(sbi); sb->s_fs_info = NULL; return -EINVAL; }
/* This function creates a new shiny flash memory control structure. */ struct jffs_fmcontrol *jffs_build_begin(struct jffs_control *c, kdev_t dev) { struct jffs_fmcontrol *fmc; struct mtd_info *mtd; D3(printk("jffs_build_begin()\n")); fmc = kmalloc(sizeof(*fmc), GFP_KERNEL); if (!fmc) { D(printk("jffs_build_begin(): Allocation of " "struct jffs_fmcontrol failed!\n")); return (struct jffs_fmcontrol *)0; } memset(fmc, 0, sizeof(struct jffs_fmcontrol)); DJM(no_jffs_fmcontrol++); mtd = get_mtd_device(NULL, MINOR(dev)); if (IS_ERR(mtd)) { kfree(fmc); DJM(no_jffs_fmcontrol--); return NULL; } #if JFFS_RAM_BLOCKS > 0 mtd->size = JFFS_RAM_BLOCKS * 64 * 1024; mtd->erasesize = 64 * 1024; #endif /* Retrieve the size of the flash memory. */ D3(printk(" fmc->flash_size = %d bytes\n", mtd->size)); fmc->free_size = fmc->flash_size = mtd->size; fmc->sector_size = mtd->erasesize; fmc->max_chunk_size = fmc->sector_size / 2; /* min_free_size: 1 sector, obviously. + 1 x max_chunk_size, for when a nodes overlaps the end of a sector + 1 x max_chunk_size again, which ought to be enough to handle the case where a rename causes a name to grow, and GC has to write out larger nodes than the ones it's obsoleting. We should fix it so it doesn't have to write the name _every_ time. Later. + another 2 sectors because people keep getting GC stuck and we don't know why. This scares me - I want formal proof of correctness of whatever number we put here. dwmw2. I know why! (rvt) 1) During a GC, the code blindly copied N bytes of the file whose node was the first non-dirty node. If some of those bytes were on a different sector (EB) they got copied, thus needlessly creating dirty nodes that were not on the head sector. In a worst case, we could create as many as 16 * 32kb = 8 sectors of needlessly dirty nodes. A pathological case was where there are several files with one (small) node on the head block followed by large node(s) (up to a total of 32KB) just before the tail. When a GC took place, the small node got copied--thereby creating free-able space on the head block--GOOD. And the large nodes also got copied--thereby creating dirty space that was very far away from the head page and therefore would not be freeable until much much later--BAD. Until a GC occurs on that block, a re-written node appears twice in the flash---once as the (old) dirty node and once as the (new) used/valid node. Worse, if there is another small node that gets GC'ed, and the re-write address range also includes the later (large & rewritten) node again, there will be ANOTHER copy of the dirty node, for *3* appearances in the flash! 2) Holes got expanded to zero bytes during a GC. There is no need to do this; we now just leave the holes as-is. N.B. I won't worry about the rename case. In a small JFFS we can't afford this safety margin. We'll just warn the user to don't do that. */ fmc->min_free_size = fmc->sector_size * 1; fmc->mtd = mtd; fmc->c = c; mutex_init(&fmc->biglock); fmc->low_free_size = fmc->free_size; fmc->low_frewst_size = fmc->free_size; return fmc; }
static int jffs2_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, struct vfsmount *mnt) { int err; struct nameidata nd; int mtdnr; if (!dev_name) return -EINVAL; D1(printk(KERN_DEBUG "jffs2_get_sb(): dev_name \"%s\"\n", dev_name)); /* The preferred way of mounting in future; especially when CONFIG_BLK_DEV is implemented - we specify the underlying MTD device by number or by name, so that we don't require block device support to be present in the kernel. */ /* FIXME: How to do the root fs this way? */ if (dev_name[0] == 'm' && dev_name[1] == 't' && dev_name[2] == 'd') { /* Probably mounting without the blkdev crap */ if (dev_name[3] == ':') { struct mtd_info *mtd; /* Mount by MTD device name */ D1(printk(KERN_DEBUG "jffs2_get_sb(): mtd:%%s, name \"%s\"\n", dev_name+4)); for (mtdnr = 0; mtdnr < MAX_MTD_DEVICES; mtdnr++) { mtd = get_mtd_device(NULL, mtdnr); if (!IS_ERR(mtd)) { if (!strcmp(mtd->name, dev_name+4)) return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd, mnt); put_mtd_device(mtd); } } printk(KERN_NOTICE "jffs2_get_sb(): MTD device with name \"%s\" not found.\n", dev_name+4); } else if (isdigit(dev_name[3])) { /* Mount by MTD device number name */ char *endptr; mtdnr = simple_strtoul(dev_name+3, &endptr, 0); if (!*endptr) { /* It was a valid number */ D1(printk(KERN_DEBUG "jffs2_get_sb(): mtd%%d, mtdnr %d\n", mtdnr)); return jffs2_get_sb_mtdnr(fs_type, flags, dev_name, data, mtdnr, mnt); } } } /* Try the old way - the hack where we allowed users to mount /dev/mtdblock$(n) but didn't actually _use_ the blkdev */ err = path_lookup(dev_name, LOOKUP_FOLLOW, &nd); D1(printk(KERN_DEBUG "jffs2_get_sb(): path_lookup() returned %d, inode %p\n", err, nd.dentry->d_inode)); if (err) return err; err = -EINVAL; if (!S_ISBLK(nd.dentry->d_inode->i_mode)) goto out; if (nd.mnt->mnt_flags & MNT_NODEV) { err = -EACCES; goto out; } if (imajor(nd.dentry->d_inode) != MTD_BLOCK_MAJOR) { if (!(flags & MS_SILENT)) printk(KERN_NOTICE "Attempt to mount non-MTD device \"%s\" as JFFS2\n", dev_name); goto out; } mtdnr = iminor(nd.dentry->d_inode); path_release(&nd); return jffs2_get_sb_mtdnr(fs_type, flags, dev_name, data, mtdnr, mnt); out: path_release(&nd); return err; }
static int __init mtd_readtest_init(void) { uint64_t tmp; int err, i; printk(KERN_INFO "\n"); printk(KERN_INFO "=================================================\n"); printk(PRINT_PREF "MTD device: %d\n", dev); mtd = get_mtd_device(NULL, dev); if (IS_ERR(mtd)) { err = PTR_ERR(mtd); printk(PRINT_PREF "error: Cannot get MTD device\n"); return err; } if (mtd->writesize == 1) { printk(PRINT_PREF "not NAND flash, assume page size is 512 " "bytes.\n"); pgsize = 512; } else pgsize = mtd->writesize; tmp = mtd->size; do_div(tmp, mtd->erasesize); ebcnt = tmp; pgcnt = mtd->erasesize / mtd->writesize; printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " "page size %u, count of eraseblocks %u, pages per " "eraseblock %u, OOB size %u\n", (unsigned long long)mtd->size, mtd->erasesize, pgsize, ebcnt, pgcnt, mtd->oobsize); err = -ENOMEM; iobuf = kmalloc(mtd->erasesize, GFP_KERNEL); if (!iobuf) { printk(PRINT_PREF "error: cannot allocate memory\n"); goto out; } iobuf1 = kmalloc(mtd->erasesize, GFP_KERNEL); if (!iobuf1) { printk(PRINT_PREF "error: cannot allocate memory\n"); goto out; } err = scan_for_bad_eraseblocks(); if (err) goto out; /* Read all eraseblocks 1 page at a time */ printk(PRINT_PREF "testing page read\n"); for (i = 0; i < ebcnt; ++i) { int ret; if (bbt[i]) continue; ret = read_eraseblock_by_page(i); if (ret) { dump_eraseblock(i); if (!err) err = ret; } cond_resched(); } if (err) printk(PRINT_PREF "finished with errors\n"); else printk(PRINT_PREF "finished\n"); out: kfree(iobuf); kfree(iobuf1); kfree(bbt); put_mtd_device(mtd); if (err) printk(PRINT_PREF "error %d occurred\n", err); printk(KERN_INFO "=================================================\n"); return err; }
static int __init mtd_stresstest_init(void) { int err; int i, op; uint64_t tmp; printk(KERN_INFO "\n"); printk(KERN_INFO "=================================================\n"); if (dev < 0) { pr_info("Please specify a valid mtd-device via module parameter\n"); pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n"); return -EINVAL; } pr_info("MTD device: %d\n", dev); mtd = get_mtd_device(NULL, dev); if (IS_ERR(mtd)) { err = PTR_ERR(mtd); pr_err("error: cannot get MTD device\n"); return err; } if (mtd->writesize == 1) { pr_info("not NAND flash, assume page size is 512 " "bytes.\n"); pgsize = 512; } else pgsize = mtd->writesize; tmp = mtd->size; do_div(tmp, mtd->erasesize); ebcnt = tmp; pgcnt = mtd->erasesize / pgsize; pr_info("MTD device size %llu, eraseblock size %u, " "page size %u, count of eraseblocks %u, pages per " "eraseblock %u, OOB size %u\n", (unsigned long long)mtd->size, mtd->erasesize, pgsize, ebcnt, pgcnt, mtd->oobsize); if (ebcnt < 2) { pr_err("error: need at least 2 eraseblocks\n"); err = -ENOSPC; goto out_put_mtd; } /* Read or write up 2 eraseblocks at a time */ bufsize = mtd->erasesize * 2; err = -ENOMEM; readbuf = vmalloc(bufsize); writebuf = vmalloc(bufsize); offsets = kmalloc(ebcnt * sizeof(int), GFP_KERNEL); if (!readbuf || !writebuf || !offsets) { pr_err("error: cannot allocate memory\n"); goto out; } for (i = 0; i < ebcnt; i++) offsets[i] = mtd->erasesize; prandom_bytes(writebuf, bufsize); err = scan_for_bad_eraseblocks(); if (err) goto out; /* Do operations */ pr_info("doing operations\n"); for (op = 0; op < count; op++) { if ((op & 1023) == 0) pr_info("%d operations done\n", op); err = do_operation(); if (err) goto out; cond_resched(); } pr_info("finished, %d operations done\n", op); out: kfree(offsets); kfree(bbt); vfree(writebuf); vfree(readbuf); out_put_mtd: put_mtd_device(mtd); if (err) pr_info("error %d occurred\n", err); printk(KERN_INFO "=================================================\n"); return err; }
static int __init tort_init(void) { int err = 0, i, infinite = !cycles_count; int bad_ebs[ebcnt]; printk(KERN_INFO "\n"); printk(KERN_INFO "=================================================\n"); printk(PRINT_PREF "Warning: this program is trying to wear out your " "flash, stop it if this is not wanted.\n"); printk(PRINT_PREF "MTD device: %d\n", dev); printk(PRINT_PREF "torture %d eraseblocks (%d-%d) of mtd%d\n", ebcnt, eb, eb + ebcnt - 1, dev); if (pgcnt) printk(PRINT_PREF "torturing just %d pages per eraseblock\n", pgcnt); printk(PRINT_PREF "write verify %s\n", check ? "enabled" : "disabled"); mtd = get_mtd_device(NULL, dev); if (IS_ERR(mtd)) { err = PTR_ERR(mtd); printk(PRINT_PREF "error: cannot get MTD device\n"); return err; } if (mtd->writesize == 1) { printk(PRINT_PREF "not NAND flash, assume page size is 512 " "bytes.\n"); pgsize = 512; } else pgsize = mtd->writesize; if (pgcnt && (pgcnt > mtd->erasesize / pgsize || pgcnt < 0)) { printk(PRINT_PREF "error: invalid pgcnt value %d\n", pgcnt); goto out_mtd; } err = -ENOMEM; patt_5A5 = kmalloc(mtd->erasesize, GFP_KERNEL); if (!patt_5A5) { printk(PRINT_PREF "error: cannot allocate memory\n"); goto out_mtd; } patt_A5A = kmalloc(mtd->erasesize, GFP_KERNEL); if (!patt_A5A) { printk(PRINT_PREF "error: cannot allocate memory\n"); goto out_patt_5A5; } patt_FF = kmalloc(mtd->erasesize, GFP_KERNEL); if (!patt_FF) { printk(PRINT_PREF "error: cannot allocate memory\n"); goto out_patt_A5A; } check_buf = kmalloc(mtd->erasesize, GFP_KERNEL); if (!check_buf) { printk(PRINT_PREF "error: cannot allocate memory\n"); goto out_patt_FF; } err = 0; /* Initialize patterns */ memset(patt_FF, 0xFF, mtd->erasesize); for (i = 0; i < mtd->erasesize / pgsize; i++) { if (!(i & 1)) { memset(patt_5A5 + i * pgsize, 0x55, pgsize); memset(patt_A5A + i * pgsize, 0xAA, pgsize); } else { memset(patt_5A5 + i * pgsize, 0xAA, pgsize); memset(patt_A5A + i * pgsize, 0x55, pgsize); } } /* * Check if there is a bad eraseblock among those we are going to test. */ memset(&bad_ebs[0], 0, sizeof(int) * ebcnt); if (mtd->block_isbad) { for (i = eb; i < eb + ebcnt; i++) { err = mtd->block_isbad(mtd, (loff_t)i * mtd->erasesize); if (err < 0) { printk(PRINT_PREF "block_isbad() returned %d " "for EB %d\n", err, i); goto out; } if (err) { printk("EB %d is bad. Skip it.\n", i); bad_ebs[i - eb] = 1; } } } start_timing(); while (1) { int i; void *patt; /* Erase all eraseblocks */ for (i = eb; i < eb + ebcnt; i++) { if (bad_ebs[i - eb]) continue; err = erase_eraseblock(i); if (err) goto out; cond_resched(); } /* Check if the eraseblocks contain only 0xFF bytes */ if (check) { for (i = eb; i < eb + ebcnt; i++) { if (bad_ebs[i - eb]) continue; err = check_eraseblock(i, patt_FF); if (err) { printk(PRINT_PREF "verify failed" " for 0xFF... pattern\n"); goto out; } cond_resched(); } } /* Write the pattern */ for (i = eb; i < eb + ebcnt; i++) { if (bad_ebs[i - eb]) continue; if ((eb + erase_cycles) & 1) patt = patt_5A5; else patt = patt_A5A; err = write_pattern(i, patt); if (err) goto out; cond_resched(); } /* Verify what we wrote */ if (check) { for (i = eb; i < eb + ebcnt; i++) { if (bad_ebs[i - eb]) continue; if ((eb + erase_cycles) & 1) patt = patt_5A5; else patt = patt_A5A; err = check_eraseblock(i, patt); if (err) { printk(PRINT_PREF "verify failed for %s" " pattern\n", ((eb + erase_cycles) & 1) ? "0x55AA55..." : "0xAA55AA..."); goto out; } cond_resched(); } } erase_cycles += 1; if (erase_cycles % gran == 0) { long ms; stop_timing(); ms = (finish.tv_sec - start.tv_sec) * 1000 + (finish.tv_usec - start.tv_usec) / 1000; printk(PRINT_PREF "%08u erase cycles done, took %lu " "milliseconds (%lu seconds)\n", erase_cycles, ms, ms / 1000); start_timing(); } if (!infinite && --cycles_count == 0) break; } out: printk(PRINT_PREF "finished after %u erase cycles\n", erase_cycles); kfree(check_buf); out_patt_FF: kfree(patt_FF); out_patt_A5A: kfree(patt_A5A); out_patt_5A5: kfree(patt_5A5); out_mtd: put_mtd_device(mtd); if (err) printk(PRINT_PREF "error %d occurred during torturing\n", err); printk(KERN_INFO "=================================================\n"); return err; }
static int __init mtd_stresstest_init(void) { int err; int i, op; uint64_t tmp; printk(KERN_INFO "\n"); printk(KERN_INFO "=================================================\n"); printk(PRINT_PREF "MTD device: %d\n", dev); mtd = get_mtd_device(NULL, dev); if (IS_ERR(mtd)) { err = PTR_ERR(mtd); printk(PRINT_PREF "error: cannot get MTD device\n"); return err; } if (mtd->writesize == 1) { printk(PRINT_PREF "not NAND flash, assume page size is 512 " "bytes.\n"); pgsize = 512; } else pgsize = mtd->writesize; tmp = mtd->size; do_div(tmp, mtd->erasesize); ebcnt = tmp; pgcnt = mtd->erasesize / mtd->writesize; printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " "page size %u, count of eraseblocks %u, pages per " "eraseblock %u, OOB size %u\n", (unsigned long long)mtd->size, mtd->erasesize, pgsize, ebcnt, pgcnt, mtd->oobsize); /* Read or write up 2 eraseblocks at a time */ bufsize = mtd->erasesize * 2; err = -ENOMEM; readbuf = vmalloc(bufsize); writebuf = vmalloc(bufsize); offsets = kmalloc(ebcnt * sizeof(int), GFP_KERNEL); if (!readbuf || !writebuf || !offsets) { printk(PRINT_PREF "error: cannot allocate memory\n"); goto out; } for (i = 0; i < ebcnt; i++) offsets[i] = mtd->erasesize; simple_srand(current->pid); for (i = 0; i < bufsize; i++) writebuf[i] = simple_rand(); err = scan_for_bad_eraseblocks(); if (err) goto out; /* Do operations */ printk(PRINT_PREF "doing operations\n"); for (op = 0; op < count; op++) { if ((op & 1023) == 0) printk(PRINT_PREF "%d operations done\n", op); err = do_operation(); if (err) goto out; cond_resched(); } printk(PRINT_PREF "finished, %d operations done\n", op); out: kfree(offsets); kfree(bbt); vfree(writebuf); vfree(readbuf); put_mtd_device(mtd); if (err) printk(PRINT_PREF "error %d occurred\n", err); printk(KERN_INFO "=================================================\n"); return err; }
static int __init mtd_oobtest_init(void) { int err = 0; unsigned int i; uint64_t tmp; struct mtd_oob_ops ops; loff_t addr = 0, addr0; printk(KERN_INFO "\n"); printk(KERN_INFO "=================================================\n"); if (dev < 0) { pr_info("Please specify a valid mtd-device via module parameter\n"); pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n"); return -EINVAL; } pr_info("MTD device: %d\n", dev); mtd = get_mtd_device(NULL, dev); if (IS_ERR(mtd)) { err = PTR_ERR(mtd); pr_err("error: cannot get MTD device\n"); return err; } if (!mtd_type_is_nand(mtd)) { pr_info("this test requires NAND flash\n"); goto out; } tmp = mtd->size; do_div(tmp, mtd->erasesize); ebcnt = tmp; pgcnt = mtd->erasesize / mtd->writesize; pr_info("MTD device size %llu, eraseblock size %u, " "page size %u, count of eraseblocks %u, pages per " "eraseblock %u, OOB size %u\n", (unsigned long long)mtd->size, mtd->erasesize, mtd->writesize, ebcnt, pgcnt, mtd->oobsize); err = -ENOMEM; readbuf = kmalloc(mtd->erasesize, GFP_KERNEL); if (!readbuf) goto out; writebuf = kmalloc(mtd->erasesize, GFP_KERNEL); if (!writebuf) goto out; bbt = kzalloc(ebcnt, GFP_KERNEL); if (!bbt) goto out; err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt); if (err) goto out; use_offset = 0; use_len = mtd->ecclayout->oobavail; use_len_max = mtd->ecclayout->oobavail; vary_offset = 0; /* First test: write all OOB, read it back and verify */ pr_info("test 1 of 5\n"); err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); if (err) goto out; prandom_seed_state(&rnd_state, 1); err = write_whole_device(); if (err) goto out; prandom_seed_state(&rnd_state, 1); err = verify_all_eraseblocks(); if (err) goto out; /* * Second test: write all OOB, a block at a time, read it back and * verify. */ pr_info("test 2 of 5\n"); err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); if (err) goto out; prandom_seed_state(&rnd_state, 3); err = write_whole_device(); if (err) goto out; /* Check all eraseblocks */ prandom_seed_state(&rnd_state, 3); pr_info("verifying all eraseblocks\n"); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; err = verify_eraseblock_in_one_go(i); if (err) goto out; if (i % 256 == 0) pr_info("verified up to eraseblock %u\n", i); cond_resched(); } pr_info("verified %u eraseblocks\n", i); /* * Third test: write OOB at varying offsets and lengths, read it back * and verify. */ pr_info("test 3 of 5\n"); err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); if (err) goto out; /* Write all eraseblocks */ use_offset = 0; use_len = mtd->ecclayout->oobavail; use_len_max = mtd->ecclayout->oobavail; vary_offset = 1; prandom_seed_state(&rnd_state, 5); err = write_whole_device(); if (err) goto out; /* Check all eraseblocks */ use_offset = 0; use_len = mtd->ecclayout->oobavail; use_len_max = mtd->ecclayout->oobavail; vary_offset = 1; prandom_seed_state(&rnd_state, 5); err = verify_all_eraseblocks(); if (err) goto out; use_offset = 0; use_len = mtd->ecclayout->oobavail; use_len_max = mtd->ecclayout->oobavail; vary_offset = 0; /* Fourth test: try to write off end of device */ pr_info("test 4 of 5\n"); err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); if (err) goto out; addr0 = 0; for (i = 0; i < ebcnt && bbt[i]; ++i) addr0 += mtd->erasesize; /* Attempt to write off end of OOB */ ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = 1; ops.oobretlen = 0; ops.ooboffs = mtd->ecclayout->oobavail; ops.datbuf = NULL; ops.oobbuf = writebuf; pr_info("attempting to start write past end of OOB\n"); pr_info("an error is expected...\n"); err = mtd_write_oob(mtd, addr0, &ops); if (err) { pr_info("error occurred as expected\n"); err = 0; } else { pr_err("error: can write past end of OOB\n"); errcnt += 1; } /* Attempt to read off end of OOB */ ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = 1; ops.oobretlen = 0; ops.ooboffs = mtd->ecclayout->oobavail; ops.datbuf = NULL; ops.oobbuf = readbuf; pr_info("attempting to start read past end of OOB\n"); pr_info("an error is expected...\n"); err = mtd_read_oob(mtd, addr0, &ops); if (err) { pr_info("error occurred as expected\n"); err = 0; } else { pr_err("error: can read past end of OOB\n"); errcnt += 1; } if (bbt[ebcnt - 1]) pr_info("skipping end of device tests because last " "block is bad\n"); else { /* Attempt to write off end of device */ ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail + 1; ops.oobretlen = 0; ops.ooboffs = 0; ops.datbuf = NULL; ops.oobbuf = writebuf; pr_info("attempting to write past end of device\n"); pr_info("an error is expected...\n"); err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops); if (err) { pr_info("error occurred as expected\n"); err = 0; } else { pr_err("error: wrote past end of device\n"); errcnt += 1; } /* Attempt to read off end of device */ ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail + 1; ops.oobretlen = 0; ops.ooboffs = 0; ops.datbuf = NULL; ops.oobbuf = readbuf; pr_info("attempting to read past end of device\n"); pr_info("an error is expected...\n"); err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops); if (err) { pr_info("error occurred as expected\n"); err = 0; } else { pr_err("error: read past end of device\n"); errcnt += 1; } err = mtdtest_erase_eraseblock(mtd, ebcnt - 1); if (err) goto out; /* Attempt to write off end of device */ ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail; ops.oobretlen = 0; ops.ooboffs = 1; ops.datbuf = NULL; ops.oobbuf = writebuf; pr_info("attempting to write past end of device\n"); pr_info("an error is expected...\n"); err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops); if (err) { pr_info("error occurred as expected\n"); err = 0; } else { pr_err("error: wrote past end of device\n"); errcnt += 1; } /* Attempt to read off end of device */ ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail; ops.oobretlen = 0; ops.ooboffs = 1; ops.datbuf = NULL; ops.oobbuf = readbuf; pr_info("attempting to read past end of device\n"); pr_info("an error is expected...\n"); err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops); if (err) { pr_info("error occurred as expected\n"); err = 0; } else { pr_err("error: read past end of device\n"); errcnt += 1; } } /* Fifth test: write / read across block boundaries */ pr_info("test 5 of 5\n"); /* Erase all eraseblocks */ err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); if (err) goto out; /* Write all eraseblocks */ prandom_seed_state(&rnd_state, 11); pr_info("writing OOBs of whole device\n"); for (i = 0; i < ebcnt - 1; ++i) { int cnt = 2; int pg; size_t sz = mtd->ecclayout->oobavail; if (bbt[i] || bbt[i + 1]) continue; addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize; prandom_bytes_state(&rnd_state, writebuf, sz * cnt); for (pg = 0; pg < cnt; ++pg) { ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = sz; ops.oobretlen = 0; ops.ooboffs = 0; ops.datbuf = NULL; ops.oobbuf = writebuf + pg * sz; err = mtd_write_oob(mtd, addr, &ops); if (err) goto out; if (i % 256 == 0) pr_info("written up to eraseblock %u\n", i); cond_resched(); addr += mtd->writesize; } } pr_info("written %u eraseblocks\n", i); /* Check all eraseblocks */ prandom_seed_state(&rnd_state, 11); pr_info("verifying all eraseblocks\n"); for (i = 0; i < ebcnt - 1; ++i) { if (bbt[i] || bbt[i + 1]) continue; prandom_bytes_state(&rnd_state, writebuf, mtd->ecclayout->oobavail * 2); addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize; ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail * 2; ops.oobretlen = 0; ops.ooboffs = 0; ops.datbuf = NULL; ops.oobbuf = readbuf; err = mtd_read_oob(mtd, addr, &ops); if (err) goto out; if (memcmp(readbuf, writebuf, mtd->ecclayout->oobavail * 2)) { pr_err("error: verify failed at %#llx\n", (long long)addr); errcnt += 1; if (errcnt > 1000) { pr_err("error: too many errors\n"); goto out; } } if (i % 256 == 0) pr_info("verified up to eraseblock %u\n", i); cond_resched(); } pr_info("verified %u eraseblocks\n", i); pr_info("finished with %d errors\n", errcnt); out: kfree(bbt); kfree(writebuf); kfree(readbuf); put_mtd_device(mtd); if (err) pr_info("error %d occurred\n", err); printk(KERN_INFO "=================================================\n"); return err; }
static int dev_nvram_init(void) { int order = 0, ret = 0; struct page *page, *end; unsigned int i; osl_t *osh; /* Allocate and reserve memory to mmap() */ while ((PAGE_SIZE << order) < nvram_space) order++; end = virt_to_page(nvram_buf + (PAGE_SIZE << order) - 1); for (page = virt_to_page(nvram_buf); page <= end; page++) { SetPageReserved(page); } #if defined(CONFIG_MTD) || defined(CONFIG_MTD_MODULE) /* Find associated MTD device */ for (i = 0; i < MAX_MTD_DEVICES; i++) { nvram_mtd = get_mtd_device(NULL, i); if (!IS_ERR(nvram_mtd)) { if (!strcmp(nvram_mtd->name, "nvram") && nvram_mtd->size >= nvram_space) { break; } put_mtd_device(nvram_mtd); } } if (i >= MAX_MTD_DEVICES) nvram_mtd = NULL; #endif /* Initialize hash table lock */ spin_lock_init(&nvram_lock); /* Initialize commit semaphore */ init_MUTEX(&nvram_sem); /* Register char device */ if ((nvram_major = register_chrdev(0, "nvram", &dev_nvram_fops)) < 0) { ret = nvram_major; goto err; } if (si_osh(sih) == NULL) { osh = osl_attach(NULL, SI_BUS, FALSE); if (osh == NULL) { printk("Error allocating osh\n"); unregister_chrdev(nvram_major, "nvram"); goto err; } si_setosh(sih, osh); } printk("dev_nvram_init: _nvram_init\n"); /* Initialize hash table */ _nvram_init((void *)sih); /* Create /dev/nvram handle */ nvram_class = class_create(THIS_MODULE, "nvram"); if (IS_ERR(nvram_class)) { printk("Error creating nvram class\n"); goto err; } /* Add the device nvram0 */ class_device_create(nvram_class, NULL, MKDEV(nvram_major, 0), NULL, "nvram"); /* reserve commit read buffer */ /* Backup sector blocks to be erased */ if (!(nvram_commit_buf = kmalloc(ROUNDUP(nvram_space, nvram_mtd->erasesize), GFP_KERNEL))) { printk("dev_nvram_init: nvram_commit_buf out of memory\n"); goto err; } /* Set the SDRAM NCDL value into NVRAM if not already done */ if (getintvar(NULL, "sdram_ncdl") == 0) { unsigned int ncdl; char buf[] = "0x00000000"; if ((ncdl = si_memc_get_ncdl(sih))) { sprintf(buf, "0x%08x", ncdl); nvram_set("sdram_ncdl", buf); nvram_commit(); } } return 0; err: dev_nvram_exit(); return ret; }
static int __init mtd_oobtest_init(void) { int err = 0; unsigned int i; uint64_t tmp; struct mtd_oob_ops ops; loff_t addr = 0, addr0; printk(KERN_INFO "\n"); printk(KERN_INFO "=================================================\n"); printk(PRINT_PREF "MTD device: %d\n", dev); mtd = get_mtd_device(NULL, dev); if (IS_ERR(mtd)) { err = PTR_ERR(mtd); printk(PRINT_PREF "error: cannot get MTD device\n"); return err; } if (mtd->type != MTD_NANDFLASH) { printk(PRINT_PREF "this test requires NAND flash\n"); goto out; } tmp = mtd->size; do_div(tmp, mtd->erasesize); ebcnt = tmp; pgcnt = mtd->erasesize / mtd->writesize; printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " "page size %u, count of eraseblocks %u, pages per " "eraseblock %u, OOB size %u\n", (unsigned long long)mtd->size, mtd->erasesize, mtd->writesize, ebcnt, pgcnt, mtd->oobsize); err = -ENOMEM; mtd->erasesize = mtd->erasesize; readbuf = kmalloc(mtd->erasesize, GFP_KERNEL); if (!readbuf) { printk(PRINT_PREF "error: cannot allocate memory\n"); goto out; } writebuf = kmalloc(mtd->erasesize, GFP_KERNEL); if (!writebuf) { printk(PRINT_PREF "error: cannot allocate memory\n"); goto out; } err = scan_for_bad_eraseblocks(); if (err) goto out; use_offset = 0; use_len = mtd->ecclayout->oobavail; use_len_max = mtd->ecclayout->oobavail; vary_offset = 0; printk(PRINT_PREF "test 1 of 5\n"); err = erase_whole_device(); if (err) goto out; simple_srand(1); err = write_whole_device(); if (err) goto out; simple_srand(1); err = verify_all_eraseblocks(); if (err) goto out; printk(PRINT_PREF "test 2 of 5\n"); err = erase_whole_device(); if (err) goto out; simple_srand(3); err = write_whole_device(); if (err) goto out; simple_srand(3); printk(PRINT_PREF "verifying all eraseblocks\n"); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; err = verify_eraseblock_in_one_go(i); if (err) goto out; if (i % 256 == 0) printk(PRINT_PREF "verified up to eraseblock %u\n", i); cond_resched(); } printk(PRINT_PREF "verified %u eraseblocks\n", i); printk(PRINT_PREF "test 3 of 5\n"); err = erase_whole_device(); if (err) goto out; use_offset = 0; use_len = mtd->ecclayout->oobavail; use_len_max = mtd->ecclayout->oobavail; vary_offset = 1; simple_srand(5); printk(PRINT_PREF "writing OOBs of whole device\n"); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; err = write_eraseblock(i); if (err) goto out; if (i % 256 == 0) printk(PRINT_PREF "written up to eraseblock %u\n", i); cond_resched(); } printk(PRINT_PREF "written %u eraseblocks\n", i); use_offset = 0; use_len = mtd->ecclayout->oobavail; use_len_max = mtd->ecclayout->oobavail; vary_offset = 1; simple_srand(5); err = verify_all_eraseblocks(); if (err) goto out; use_offset = 0; use_len = mtd->ecclayout->oobavail; use_len_max = mtd->ecclayout->oobavail; vary_offset = 0; printk(PRINT_PREF "test 4 of 5\n"); err = erase_whole_device(); if (err) goto out; addr0 = 0; for (i = 0; i < ebcnt && bbt[i]; ++i) addr0 += mtd->erasesize; ops.mode = MTD_OOB_AUTO; ops.len = 0; ops.retlen = 0; ops.ooblen = 1; ops.oobretlen = 0; ops.ooboffs = mtd->ecclayout->oobavail; ops.datbuf = NULL; ops.oobbuf = writebuf; printk(PRINT_PREF "attempting to start write past end of OOB\n"); printk(PRINT_PREF "an error is expected...\n"); err = mtd->write_oob(mtd, addr0, &ops); if (err) { printk(PRINT_PREF "error occurred as expected\n"); err = 0; } else { printk(PRINT_PREF "error: can write past end of OOB\n"); errcnt += 1; } ops.mode = MTD_OOB_AUTO; ops.len = 0; ops.retlen = 0; ops.ooblen = 1; ops.oobretlen = 0; ops.ooboffs = mtd->ecclayout->oobavail; ops.datbuf = NULL; ops.oobbuf = readbuf; printk(PRINT_PREF "attempting to start read past end of OOB\n"); printk(PRINT_PREF "an error is expected...\n"); err = mtd->read_oob(mtd, addr0, &ops); if (err) { printk(PRINT_PREF "error occurred as expected\n"); err = 0; } else { printk(PRINT_PREF "error: can read past end of OOB\n"); errcnt += 1; } if (bbt[ebcnt - 1]) printk(PRINT_PREF "skipping end of device tests because last " "block is bad\n"); else { ops.mode = MTD_OOB_AUTO; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail + 1; ops.oobretlen = 0; ops.ooboffs = 0; ops.datbuf = NULL; ops.oobbuf = writebuf; printk(PRINT_PREF "attempting to write past end of device\n"); printk(PRINT_PREF "an error is expected...\n"); err = mtd->write_oob(mtd, mtd->size - mtd->writesize, &ops); if (err) { printk(PRINT_PREF "error occurred as expected\n"); err = 0; } else { printk(PRINT_PREF "error: wrote past end of device\n"); errcnt += 1; } ops.mode = MTD_OOB_AUTO; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail + 1; ops.oobretlen = 0; ops.ooboffs = 0; ops.datbuf = NULL; ops.oobbuf = readbuf; printk(PRINT_PREF "attempting to read past end of device\n"); printk(PRINT_PREF "an error is expected...\n"); err = mtd->read_oob(mtd, mtd->size - mtd->writesize, &ops); if (err) { printk(PRINT_PREF "error occurred as expected\n"); err = 0; } else { printk(PRINT_PREF "error: read past end of device\n"); errcnt += 1; } err = erase_eraseblock(ebcnt - 1); if (err) goto out; ops.mode = MTD_OOB_AUTO; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail; ops.oobretlen = 0; ops.ooboffs = 1; ops.datbuf = NULL; ops.oobbuf = writebuf; printk(PRINT_PREF "attempting to write past end of device\n"); printk(PRINT_PREF "an error is expected...\n"); err = mtd->write_oob(mtd, mtd->size - mtd->writesize, &ops); if (err) { printk(PRINT_PREF "error occurred as expected\n"); err = 0; } else { printk(PRINT_PREF "error: wrote past end of device\n"); errcnt += 1; } ops.mode = MTD_OOB_AUTO; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail; ops.oobretlen = 0; ops.ooboffs = 1; ops.datbuf = NULL; ops.oobbuf = readbuf; printk(PRINT_PREF "attempting to read past end of device\n"); printk(PRINT_PREF "an error is expected...\n"); err = mtd->read_oob(mtd, mtd->size - mtd->writesize, &ops); if (err) { printk(PRINT_PREF "error occurred as expected\n"); err = 0; } else { printk(PRINT_PREF "error: read past end of device\n"); errcnt += 1; } } printk(PRINT_PREF "test 5 of 5\n"); err = erase_whole_device(); if (err) goto out; simple_srand(11); printk(PRINT_PREF "writing OOBs of whole device\n"); for (i = 0; i < ebcnt - 1; ++i) { int cnt = 2; int pg; size_t sz = mtd->ecclayout->oobavail; if (bbt[i] || bbt[i + 1]) continue; addr = (i + 1) * mtd->erasesize - mtd->writesize; for (pg = 0; pg < cnt; ++pg) { set_random_data(writebuf, sz); ops.mode = MTD_OOB_AUTO; ops.len = 0; ops.retlen = 0; ops.ooblen = sz; ops.oobretlen = 0; ops.ooboffs = 0; ops.datbuf = NULL; ops.oobbuf = writebuf; err = mtd->write_oob(mtd, addr, &ops); if (err) goto out; if (i % 256 == 0) printk(PRINT_PREF "written up to eraseblock " "%u\n", i); cond_resched(); addr += mtd->writesize; } } printk(PRINT_PREF "written %u eraseblocks\n", i); simple_srand(11); printk(PRINT_PREF "verifying all eraseblocks\n"); for (i = 0; i < ebcnt - 1; ++i) { if (bbt[i] || bbt[i + 1]) continue; set_random_data(writebuf, mtd->ecclayout->oobavail * 2); addr = (i + 1) * mtd->erasesize - mtd->writesize; ops.mode = MTD_OOB_AUTO; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail * 2; ops.oobretlen = 0; ops.ooboffs = 0; ops.datbuf = NULL; ops.oobbuf = readbuf; err = mtd->read_oob(mtd, addr, &ops); if (err) goto out; if (memcmp(readbuf, writebuf, mtd->ecclayout->oobavail * 2)) { printk(PRINT_PREF "error: verify failed at %#llx\n", (long long)addr); errcnt += 1; if (errcnt > 1000) { printk(PRINT_PREF "error: too many errors\n"); goto out; } } if (i % 256 == 0) printk(PRINT_PREF "verified up to eraseblock %u\n", i); cond_resched(); } printk(PRINT_PREF "verified %u eraseblocks\n", i); printk(PRINT_PREF "finished with %d errors\n", errcnt); out: kfree(bbt); kfree(writebuf); kfree(readbuf); put_mtd_device(mtd); if (err) printk(PRINT_PREF "error %d occurred\n", err); printk(KERN_INFO "=================================================\n"); return err; }
static int __init nandflash_ecctest_init(void) { unsigned int read_len = 0; int err = 0; loff_t offset = 0; unsigned int j = 0; struct rnd_state rnd_state; unsigned int corrected_num = 0; unsigned char *oobbuf_w = NULL; unsigned char *oobbuf_r = NULL; unsigned char *pagebuf_r = NULL; unsigned char *pagebuf_w = NULL; unsigned char *pagebuf_v = NULL; struct mtd_ecc_stats stats = {0}; struct mtd_part *mtd_part = NULL; printk("\n"); pr_info("--------------------------------------------------------------------------\n"); /*prepare work*/ mtd = get_mtd_device(NULL, 4); if (IS_ERR(mtd)) { err = PTR_ERR(mtd); pr_err("Cannot get MTD device\n"); return err; } mtd_part = (struct mtd_part *)mtd; if(!mtd->_block_isbad || !mtd->_block_markbad || !mtd->_read_oob || !mtd->_write_oob || !mtd->_read || !mtd->_write) { pr_err("Some mtd's method may be NULL!"); goto out; } pagebuf_r = vmalloc(mtd->writesize); oobbuf_r = vmalloc(mtd->oobsize); pagebuf_w = vmalloc(mtd->writesize); pagebuf_v = vmalloc(mtd->writesize); oobbuf_w = vmalloc(mtd->oobsize); if(!pagebuf_r || !oobbuf_r || !pagebuf_w || !pagebuf_v || !oobbuf_w) { pr_err("Alloc buf failed!"); goto out; } //find a vailid block while(offset < mtd->size) { if(mtd->_block_isbad(mtd, offset)) { offset += mtd->erasesize; } else { break; } } if(offset >= mtd->size) { pr_err("The whole mtd_partion are bad!\n"); goto out; } err = erase_eraseblock(((long)offset)/mtd->erasesize); if(err) { pr_err("Erase failed at EB: %d\n", ((unsigned int)offset)/mtd->erasesize); goto out; } pr_info("Erase block %d successfully!\n", ((unsigned int)offset)/mtd->erasesize); //prepare value prandom_seed_state(&rnd_state, 1); prandom_bytes_state(&rnd_state, oobbuf_w, mtd->oobsize); prandom_bytes_state(&rnd_state, pagebuf_w, mtd->writesize); memcpy(pagebuf_v, pagebuf_w, mtd->writesize); err = write_oob(offset, pagebuf_w, mtd->writesize, oobbuf_w, mtd->oobsize, MTD_OPS_PLACE_OOB); if(err != 0) { pr_err("1.1 write failed!\n"); goto erase; } err = read_oob(offset, pagebuf_r, mtd->writesize, oobbuf_r, mtd->oobsize, MTD_OPS_PLACE_OOB); if(err != 0) { pr_err("1.1 read failed!\n"); goto erase; } if(memcmp(pagebuf_v, pagebuf_r, mtd->writesize) != 0) { pr_err("1.1 compare page failed!\n"); goto erase; } memcpy(oobbuf_w, oobbuf_r, mtd->oobsize); for(j = 0; j < mtd->writesize * 8; j ++) { offset += mtd->writesize; err = insert_biterror(pagebuf_w); if(err) { pr_err("Insert biterror failed!\n"); goto erase; } pr_info("Insert %d bit-flip sucessfully!\n", j + 1); err = write_oob(offset, pagebuf_w, mtd->writesize, oobbuf_w, mtd->oobsize, MTD_OPS_RAW); if(err != 0) { pr_err("2.1 write failed!\n"); goto erase; } stats = mtd_part->master->ecc_stats; err = read_oob(offset, pagebuf_r, mtd->writesize, oobbuf_r, mtd->oobsize, MTD_OPS_PLACE_OOB); if(err != 0) { pr_err("2.1 read failed!\n"); break; } if(memcmp(pagebuf_v, pagebuf_r, mtd->writesize) != 0) { pr_err("2.2 compare page failed!\n"); goto erase; } corrected_num = mtd_part->master->ecc_stats.corrected - stats.corrected; if(corrected_num != (j + 1)) { pr_err("Bit-flip num is not match, expected:%d, really:%d\n", j + 1, corrected_num); goto erase; } } pr_info("Test successfully, this system can corrected %d bit-flip at most!\n", j); erase: err = erase_eraseblock(((unsigned int)offset)/mtd->erasesize); if(err) { pr_err("1.3 erase failed at EB: %d\n", ((unsigned int)offset)/mtd->erasesize); goto out; } out: vfree(pagebuf_r); vfree(oobbuf_r); vfree(pagebuf_w); vfree(oobbuf_w); pr_info("--------------------------------------------------------------------------\n"); return -1; }
/* * set up an MTD-based superblock */ int get_sb_mtd(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, int (*fill_super)(struct super_block *, void *, int), struct vfsmount *mnt) { #ifdef CONFIG_BLOCK struct block_device *bdev; int ret, major; #endif int mtdnr; if (!dev_name) return -EINVAL; DEBUG(2, "MTDSB: dev_name \"%s\"\n", dev_name); /* the preferred way of mounting in future; especially when * CONFIG_BLOCK=n - we specify the underlying MTD device by number or * by name, so that we don't require block device support to be present * in the kernel. */ if (dev_name[0] == 'm' && dev_name[1] == 't' && dev_name[2] == 'd') { if (dev_name[3] == ':') { struct mtd_info *mtd; /* mount by MTD device name */ DEBUG(1, "MTDSB: mtd:%%s, name \"%s\"\n", dev_name + 4); for (mtdnr = 0; mtdnr < MAX_MTD_DEVICES; mtdnr++) { mtd = get_mtd_device(NULL, mtdnr); if (!IS_ERR(mtd)) { if (!strcmp(mtd->name, dev_name + 4)) return get_sb_mtd_aux( fs_type, flags, dev_name, data, mtd, fill_super, mnt); put_mtd_device(mtd); } } printk(KERN_NOTICE "MTD:" " MTD device with name \"%s\" not found.\n", dev_name + 4); } else if (isdigit(dev_name[3])) { /* mount by MTD device number name */ char *endptr; mtdnr = simple_strtoul(dev_name + 3, &endptr, 0); if (!*endptr) { /* It was a valid number */ DEBUG(1, "MTDSB: mtd%%d, mtdnr %d\n", mtdnr); return get_sb_mtd_nr(fs_type, flags, dev_name, data, mtdnr, fill_super, mnt); } } } #ifdef CONFIG_BLOCK /* try the old way - the hack where we allowed users to mount * /dev/mtdblock$(n) but didn't actually _use_ the blockdev */ bdev = lookup_bdev(dev_name); if (IS_ERR(bdev)) { ret = PTR_ERR(bdev); DEBUG(1, "MTDSB: lookup_bdev() returned %d\n", ret); return ret; } DEBUG(1, "MTDSB: lookup_bdev() returned 0\n"); ret = -EINVAL; major = MAJOR(bdev->bd_dev); mtdnr = MINOR(bdev->bd_dev); bdput(bdev); if (major != MTD_BLOCK_MAJOR) goto not_an_MTD_device; return get_sb_mtd_nr(fs_type, flags, dev_name, data, mtdnr, fill_super, mnt); not_an_MTD_device: #endif /* CONFIG_BLOCK */ if (!(flags & MS_SILENT)) printk(KERN_NOTICE "MTD: Attempt to mount non-MTD device \"%s\"\n", dev_name); return -EINVAL; }
static int __init mtd_readtest_init(void) { uint64_t tmp; int err, i; printk(KERN_INFO "\n"); printk(KERN_INFO "=================================================\n"); if (dev < 0) { pr_info("Please specify a valid mtd-device via module parameter\n"); return -EINVAL; } pr_info("MTD device: %d\n", dev); mtd = get_mtd_device(NULL, dev); if (IS_ERR(mtd)) { err = PTR_ERR(mtd); pr_err("error: Cannot get MTD device\n"); return err; } if (mtd->writesize == 1) { pr_info("not NAND flash, assume page size is 512 " "bytes.\n"); pgsize = 512; } else pgsize = mtd->writesize; tmp = mtd->size; do_div(tmp, mtd->erasesize); ebcnt = tmp; pgcnt = mtd->erasesize / pgsize; pr_info("MTD device size %llu, eraseblock size %u, " "page size %u, count of eraseblocks %u, pages per " "eraseblock %u, OOB size %u\n", (unsigned long long)mtd->size, mtd->erasesize, pgsize, ebcnt, pgcnt, mtd->oobsize); err = -ENOMEM; iobuf = kmalloc(mtd->erasesize, GFP_KERNEL); if (!iobuf) goto out; iobuf1 = kmalloc(mtd->erasesize, GFP_KERNEL); if (!iobuf1) goto out; bbt = kzalloc(ebcnt, GFP_KERNEL); if (!bbt) goto out; err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt); if (err) goto out; /* Read all eraseblocks 1 page at a time */ pr_info("testing page read\n"); for (i = 0; i < ebcnt; ++i) { int ret; if (bbt[i]) continue; ret = read_eraseblock_by_page(i); if (ret) { dump_eraseblock(i); if (!err) err = ret; } ret = mtdtest_relax(); if (ret) { err = ret; goto out; } } if (err) pr_info("finished with errors\n"); else pr_info("finished\n"); out: kfree(iobuf); kfree(iobuf1); kfree(bbt); put_mtd_device(mtd); if (err) pr_info("error %d occurred\n", err); printk(KERN_INFO "=================================================\n"); return err; }
/****************************************************************************** * * axfs_get_sb_mtd * * Description: * Populates a axfs_fill_super_info struct after sanity checking the * mtd device given by a name * * Parameters: * (IN) dev_name - the mtd device name * * Returns: * pointer to a axfs_file_super_info or an error pointer * *****************************************************************************/ static struct axfs_fill_super_info *axfs_get_sb_mtd(const char *dev_name) { int mtdnr; struct nameidata nd; int err; struct axfs_fill_super_info *output; err = path_lookup(dev_name, LOOKUP_FOLLOW, &nd); if (!err) { /* Looking for a real and valid mtd device to attach to */ if (imajor(nd.path.dentry->d_inode) == MTD_BLOCK_MAJOR) { mtdnr = iminor(nd.path.dentry->d_inode); } else if (imajor(nd.path.dentry->d_inode) == MTD_CHAR_MAJOR) { mtdnr = iminor(nd.path.dentry->d_inode); mtdnr = mtdnr / 2; } else if (nd.path.mnt->mnt_flags & MNT_NODEV) { err = -EACCES; goto out; } else { goto out; } } else if (dev_name[0] == 'm' && dev_name[1] == 't' && dev_name[2] == 'd') { /* Mount from a mtd device but not a valid /dev/mtdXXX */ if (dev_name[3] == ':') { struct mtd_info *mtd; int i; /* Mount by MTD device name */ printk(KERN_DEBUG "axfs_get_sb_mtd(): mtd:%%s, name \"%s\"\n", dev_name + 4); mtdnr = -1; for (i = 0; i < MAX_MTD_DEVICES; i++) { mtd = get_mtd_device(NULL, i); if (mtd) { if (!strcmp(mtd->name, dev_name + 4)) { put_mtd_device(mtd); mtdnr = i; break; } put_mtd_device(mtd); } } if (mtdnr == -1) { printk(KERN_NOTICE "axfs_get_sb_mtd(): MTD device with name \"%s\" not found.\n", dev_name + 4); err = -EINVAL; goto out; } } else if (isdigit(dev_name[3])) { /* Mount by MTD device number */ char *endptr; mtdnr = simple_strtoul(dev_name + 3, &endptr, 0); if (*endptr) { printk(KERN_NOTICE "axfs_get_sb_mtd(): MTD device number \"%s\" not found.\n", dev_name + 3); err = -EINVAL; goto out; } } else { err = -EINVAL; goto out; } } else { err = -EINVAL; goto out; } output = axfs_get_sb_mtdnr(mtdnr); if (IS_ERR(output)) { err = PTR_ERR(output); goto out; } path_put(&nd.path); return output; out: path_put(&nd.path); printk(KERN_NOTICE "axfs_get_sb_mtd(): Invalid device \"%s\"\n",dev_name); return ERR_PTR(err); }
static int __init mtd_speedtest_init(void) { int err, i; long speed; uint64_t tmp; printk(KERN_INFO "\n"); printk(KERN_INFO "=================================================\n"); printk(PRINT_PREF "MTD device: %d\n", dev); mtd = get_mtd_device(NULL, dev); if (IS_ERR(mtd)) { err = PTR_ERR(mtd); printk(PRINT_PREF "error: cannot get MTD device\n"); return err; } if (mtd->writesize == 1) { printk(PRINT_PREF "not NAND flash, assume page size is 512 " "bytes.\n"); pgsize = 512; } else pgsize = mtd->writesize; tmp = mtd->size; do_div(tmp, mtd->erasesize); ebcnt = tmp; pgcnt = mtd->erasesize / pgsize; printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " "page size %u, count of eraseblocks %u, pages per " "eraseblock %u, OOB size %u\n", (unsigned long long)mtd->size, mtd->erasesize, pgsize, ebcnt, pgcnt, mtd->oobsize); err = -ENOMEM; iobuf = kmalloc(mtd->erasesize, GFP_KERNEL); if (!iobuf) { printk(PRINT_PREF "error: cannot allocate memory\n"); goto out; } simple_srand(1); set_random_data(iobuf, mtd->erasesize); err = scan_for_bad_eraseblocks(); if (err) goto out; err = erase_whole_device(); if (err) goto out; /* Write all eraseblocks, 1 eraseblock at a time */ printk(PRINT_PREF "testing eraseblock write speed\n"); start_timing(); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; err = write_eraseblock(i); if (err) goto out; cond_resched(); } stop_timing(); speed = calc_speed(); printk(PRINT_PREF "eraseblock write speed is %ld KiB/s\n", speed); /* Read all eraseblocks, 1 eraseblock at a time */ printk(PRINT_PREF "testing eraseblock read speed\n"); start_timing(); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; err = read_eraseblock(i); if (err) goto out; cond_resched(); } stop_timing(); speed = calc_speed(); printk(PRINT_PREF "eraseblock read speed is %ld KiB/s\n", speed); err = erase_whole_device(); if (err) goto out; /* Write all eraseblocks, 1 page at a time */ printk(PRINT_PREF "testing page write speed\n"); start_timing(); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; err = write_eraseblock_by_page(i); if (err) goto out; cond_resched(); } stop_timing(); speed = calc_speed(); printk(PRINT_PREF "page write speed is %ld KiB/s\n", speed); /* Read all eraseblocks, 1 page at a time */ printk(PRINT_PREF "testing page read speed\n"); start_timing(); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; err = read_eraseblock_by_page(i); if (err) goto out; cond_resched(); } stop_timing(); speed = calc_speed(); printk(PRINT_PREF "page read speed is %ld KiB/s\n", speed); err = erase_whole_device(); if (err) goto out; /* Write all eraseblocks, 2 pages at a time */ printk(PRINT_PREF "testing 2 page write speed\n"); start_timing(); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; err = write_eraseblock_by_2pages(i); if (err) goto out; cond_resched(); } stop_timing(); speed = calc_speed(); printk(PRINT_PREF "2 page write speed is %ld KiB/s\n", speed); /* Read all eraseblocks, 2 pages at a time */ printk(PRINT_PREF "testing 2 page read speed\n"); start_timing(); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; err = read_eraseblock_by_2pages(i); if (err) goto out; cond_resched(); } stop_timing(); speed = calc_speed(); printk(PRINT_PREF "2 page read speed is %ld KiB/s\n", speed); /* Erase all eraseblocks */ printk(PRINT_PREF "Testing erase speed\n"); start_timing(); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; err = erase_eraseblock(i); if (err) goto out; cond_resched(); } stop_timing(); speed = calc_speed(); printk(PRINT_PREF "erase speed is %ld KiB/s\n", speed); printk(PRINT_PREF "finished\n"); out: kfree(iobuf); kfree(bbt); put_mtd_device(mtd); if (err) printk(PRINT_PREF "error %d occurred\n", err); printk(KERN_INFO "=================================================\n"); return err; }
static int __init mtd_subpagetest_init(void) { int err = 0; uint32_t i; uint64_t tmp; printk(KERN_INFO "\n"); printk(KERN_INFO "=================================================\n"); printk(PRINT_PREF "MTD device: %d\n", dev); mtd = get_mtd_device(NULL, dev); if (IS_ERR(mtd)) { err = PTR_ERR(mtd); printk(PRINT_PREF "error: cannot get MTD device\n"); return err; } if (mtd->type != MTD_NANDFLASH) { printk(PRINT_PREF "this test requires NAND flash\n"); goto out; } subpgsize = mtd->writesize >> mtd->subpage_sft; tmp = mtd->size; do_div(tmp, mtd->erasesize); ebcnt = tmp; pgcnt = mtd->erasesize / mtd->writesize; printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " "page size %u, subpage size %u, count of eraseblocks %u, " "pages per eraseblock %u, OOB size %u\n", (unsigned long long)mtd->size, mtd->erasesize, mtd->writesize, subpgsize, ebcnt, pgcnt, mtd->oobsize); err = -ENOMEM; bufsize = subpgsize * 32; writebuf = kmalloc(bufsize, GFP_KERNEL); if (!writebuf) { printk(PRINT_PREF "error: cannot allocate memory\n"); goto out; } readbuf = kmalloc(bufsize, GFP_KERNEL); if (!readbuf) { printk(PRINT_PREF "error: cannot allocate memory\n"); goto out; } err = scan_for_bad_eraseblocks(); if (err) goto out; err = erase_whole_device(); if (err) goto out; printk(PRINT_PREF "writing whole device\n"); simple_srand(1); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; err = write_eraseblock(i); if (unlikely(err)) goto out; if (i % 256 == 0) printk(PRINT_PREF "written up to eraseblock %u\n", i); cond_resched(); } printk(PRINT_PREF "written %u eraseblocks\n", i); simple_srand(1); printk(PRINT_PREF "verifying all eraseblocks\n"); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; err = verify_eraseblock(i); if (unlikely(err)) goto out; if (i % 256 == 0) printk(PRINT_PREF "verified up to eraseblock %u\n", i); cond_resched(); } printk(PRINT_PREF "verified %u eraseblocks\n", i); err = erase_whole_device(); if (err) goto out; err = verify_all_eraseblocks_ff(); if (err) goto out; /* Write all eraseblocks */ simple_srand(3); printk(PRINT_PREF "writing whole device\n"); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; err = write_eraseblock2(i); if (unlikely(err)) goto out; if (i % 256 == 0) printk(PRINT_PREF "written up to eraseblock %u\n", i); cond_resched(); } printk(PRINT_PREF "written %u eraseblocks\n", i); /* Check all eraseblocks */ simple_srand(3); printk(PRINT_PREF "verifying all eraseblocks\n"); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; err = verify_eraseblock2(i); if (unlikely(err)) goto out; if (i % 256 == 0) printk(PRINT_PREF "verified up to eraseblock %u\n", i); cond_resched(); } printk(PRINT_PREF "verified %u eraseblocks\n", i); err = erase_whole_device(); if (err) goto out; err = verify_all_eraseblocks_ff(); if (err) goto out; printk(PRINT_PREF "finished with %d errors\n", errcnt); out: kfree(bbt); kfree(readbuf); kfree(writebuf); put_mtd_device(mtd); if (err) printk(PRINT_PREF "error %d occurred\n", err); printk(KERN_INFO "=================================================\n"); return err; }
static int dev_nvram_init(void) { int order = 0, ret = 0; struct page *page, *end; osl_t *osh; #if defined(CONFIG_MTD) || defined(CONFIG_MTD_MODULE) unsigned int i; #endif /* Allocate and reserve memory to mmap() */ while ((PAGE_SIZE << order) < nvram_space) order++; end = virt_to_page(nvram_buf + (PAGE_SIZE << order) - 1); for (page = virt_to_page(nvram_buf); page <= end; page++) { SetPageReserved(page); } #if defined(CONFIG_MTD) || defined(CONFIG_MTD_MODULE) /* Find associated MTD device */ for (i = 0; i < MAX_MTD_DEVICES; i++) { nvram_mtd = get_mtd_device(NULL, i); if (!IS_ERR(nvram_mtd)) { if (!strcmp(nvram_mtd->name, "nvram") && nvram_mtd->size >= nvram_space) { break; } put_mtd_device(nvram_mtd); } } if (i >= MAX_MTD_DEVICES) nvram_mtd = NULL; #endif /* Initialize hash table lock */ spin_lock_init(&nvram_lock); /* Initialize commit semaphore */ init_MUTEX(&nvram_sem); /* Register char device */ if ((nvram_major = register_chrdev(0, "nvram", &dev_nvram_fops)) < 0) { ret = nvram_major; goto err; } if (si_osh(sih) == NULL) { osh = osl_attach(NULL, SI_BUS, FALSE); if (osh == NULL) { printk("Error allocating osh\n"); unregister_chrdev(nvram_major, "nvram"); goto err; } si_setosh(sih, osh); } /* Initialize hash table */ _nvram_init(sih); /* Create /dev/nvram handle */ nvram_class = class_create(THIS_MODULE, "nvram"); if (IS_ERR(nvram_class)) { printk("Error creating nvram class\n"); goto err; } /* Add the device nvram0 */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) class_device_create(nvram_class, NULL, MKDEV(nvram_major, 0), NULL, "nvram"); #else /* Linux 2.6.36 and above */ device_create(nvram_class, NULL, MKDEV(nvram_major, 0), NULL, "nvram"); #endif /* Linux 2.6.36 */ return 0; err: dev_nvram_exit(); return ret; }
static int ctrl_cdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int err = 0; void __user *argp = (void __user *)arg; if (!capable(CAP_SYS_RESOURCE)) return -EPERM; switch (cmd) { /* Attach an MTD device command */ case UBI_IOCATT: { struct ubi_attach_req req; struct mtd_info *mtd; dbg_msg("attach MTD device"); err = copy_from_user(&req, argp, sizeof(struct ubi_attach_req)); if (err) { err = -EFAULT; break; } if (req.mtd_num < 0 || (req.ubi_num < 0 && req.ubi_num != UBI_DEV_NUM_AUTO)) { err = -EINVAL; break; } mtd = get_mtd_device(NULL, req.mtd_num); if (IS_ERR(mtd)) { err = PTR_ERR(mtd); break; } /* * Note, further request verification is done by * 'ubi_attach_mtd_dev()'. */ mutex_lock(&ubi_devices_mutex); err = ubi_attach_mtd_dev(mtd, req.ubi_num, req.vid_hdr_offset); mutex_unlock(&ubi_devices_mutex); if (err < 0) put_mtd_device(mtd); else /* @err contains UBI device number */ err = put_user(err, (__user int32_t *)argp); break; } /* Detach an MTD device command */ case UBI_IOCDET: { int ubi_num; dbg_msg("dettach MTD device"); err = get_user(ubi_num, (__user int32_t *)argp); if (err) { err = -EFAULT; break; } mutex_lock(&ubi_devices_mutex); err = ubi_detach_mtd_dev(ubi_num, 0); mutex_unlock(&ubi_devices_mutex); break; } default: err = -ENOTTY; break; } return err; }
static int __init mtd_pagetest_init(void) { int err = 0; uint64_t tmp; uint32_t i; #ifdef CONFIG_DEBUG_PRINTK printk(KERN_INFO "\n"); #else ; #endif #ifdef CONFIG_DEBUG_PRINTK printk(KERN_INFO "=================================================\n"); #else ; #endif #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "MTD device: %d\n", dev); #else ; #endif mtd = get_mtd_device(NULL, dev); if (IS_ERR(mtd)) { err = PTR_ERR(mtd); #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "error: cannot get MTD device\n"); #else ; #endif return err; } if (mtd->type != MTD_NANDFLASH) { #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "this test requires NAND flash\n"); #else ; #endif goto out; } tmp = mtd->size; do_div(tmp, mtd->erasesize); ebcnt = tmp; pgcnt = mtd->erasesize / mtd->writesize; pgsize = mtd->writesize; #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " "page size %u, count of eraseblocks %u, pages per " "eraseblock %u, OOB size %u\n", (unsigned long long)mtd->size, mtd->erasesize, pgsize, ebcnt, pgcnt, mtd->oobsize); #else ; #endif err = -ENOMEM; bufsize = pgsize * 2; writebuf = kmalloc(mtd->erasesize, GFP_KERNEL); if (!writebuf) { #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "error: cannot allocate memory\n"); #else ; #endif goto out; } twopages = kmalloc(bufsize, GFP_KERNEL); if (!twopages) { #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "error: cannot allocate memory\n"); #else ; #endif goto out; } boundary = kmalloc(bufsize, GFP_KERNEL); if (!boundary) { #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "error: cannot allocate memory\n"); #else ; #endif goto out; } err = scan_for_bad_eraseblocks(); if (err) goto out; /* Erase all eraseblocks */ #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "erasing whole device\n"); #else ; #endif for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; err = erase_eraseblock(i); if (err) goto out; cond_resched(); } #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "erased %u eraseblocks\n", i); #else ; #endif /* Write all eraseblocks */ simple_srand(1); #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "writing whole device\n"); #else ; #endif for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; err = write_eraseblock(i); if (err) goto out; if (i % 256 == 0) #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "written up to eraseblock %u\n", i); #else ; #endif cond_resched(); } #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "written %u eraseblocks\n", i); #else ; #endif /* Check all eraseblocks */ simple_srand(1); #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "verifying all eraseblocks\n"); #else ; #endif for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; err = verify_eraseblock(i); if (err) goto out; if (i % 256 == 0) #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "verified up to eraseblock %u\n", i); #else ; #endif cond_resched(); } #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "verified %u eraseblocks\n", i); #else ; #endif err = crosstest(); if (err) goto out; err = erasecrosstest(); if (err) goto out; err = erasetest(); if (err) goto out; #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "finished with %d errors\n", errcnt); #else ; #endif out: kfree(bbt); kfree(boundary); kfree(twopages); kfree(writebuf); put_mtd_device(mtd); if (err) #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "error %d occurred\n", err); #else ; #endif #ifdef CONFIG_DEBUG_PRINTK printk(KERN_INFO "=================================================\n"); #else ; #endif return err; }
static int __init tort_init(void) { int err = 0, i, infinite = !cycles_count; int bad_ebs[ebcnt]; ; ; // printk(PRINT_PREF "Warning: this program is trying to wear out your " ; ; // printk(PRINT_PREF "torture %d eraseblocks (%d-%d) of mtd%d\n", ; if (pgcnt) // printk(PRINT_PREF "torturing just %d pages per eraseblock\n", ; ; mtd = get_mtd_device(NULL, dev); if (IS_ERR(mtd)) { err = PTR_ERR(mtd); ; return err; } if (mtd->writesize == 1) { // printk(PRINT_PREF "not NAND flash, assume page size is 512 " ; pgsize = 512; } else pgsize = mtd->writesize; if (pgcnt && (pgcnt > mtd->erasesize / pgsize || pgcnt < 0)) { ; goto out_mtd; } err = -ENOMEM; patt_5A5 = kmalloc(mtd->erasesize, GFP_KERNEL); if (!patt_5A5) { ; goto out_mtd; } patt_A5A = kmalloc(mtd->erasesize, GFP_KERNEL); if (!patt_A5A) { ; goto out_patt_5A5; } patt_FF = kmalloc(mtd->erasesize, GFP_KERNEL); if (!patt_FF) { ; goto out_patt_A5A; } check_buf = kmalloc(mtd->erasesize, GFP_KERNEL); if (!check_buf) { ; goto out_patt_FF; } err = 0; /* Initialize patterns */ memset(patt_FF, 0xFF, mtd->erasesize); for (i = 0; i < mtd->erasesize / pgsize; i++) { if (!(i & 1)) { memset(patt_5A5 + i * pgsize, 0x55, pgsize); memset(patt_A5A + i * pgsize, 0xAA, pgsize); } else { memset(patt_5A5 + i * pgsize, 0xAA, pgsize); memset(patt_A5A + i * pgsize, 0x55, pgsize); } } /* * Check if there is a bad eraseblock among those we are going to test. */ memset(&bad_ebs[0], 0, sizeof(int) * ebcnt); if (mtd->block_isbad) { for (i = eb; i < eb + ebcnt; i++) { err = mtd->block_isbad(mtd, (loff_t)i * mtd->erasesize); if (err < 0) { // printk(PRINT_PREF "block_isbad() returned %d " ; goto out; } if (err) { ; bad_ebs[i - eb] = 1; } } } start_timing(); while (1) { int i; void *patt; /* Erase all eraseblocks */ for (i = eb; i < eb + ebcnt; i++) { if (bad_ebs[i - eb]) continue; err = erase_eraseblock(i); if (err) goto out; cond_resched(); } /* Check if the eraseblocks contain only 0xFF bytes */ if (check) { for (i = eb; i < eb + ebcnt; i++) { if (bad_ebs[i - eb]) continue; err = check_eraseblock(i, patt_FF); if (err) { // printk(PRINT_PREF "verify failed" ; goto out; } cond_resched(); } } /* Write the pattern */ for (i = eb; i < eb + ebcnt; i++) { if (bad_ebs[i - eb]) continue; if ((eb + erase_cycles) & 1) patt = patt_5A5; else patt = patt_A5A; err = write_pattern(i, patt); if (err) goto out; cond_resched(); } /* Verify what we wrote */ if (check) { for (i = eb; i < eb + ebcnt; i++) { if (bad_ebs[i - eb]) continue; if ((eb + erase_cycles) & 1) patt = patt_5A5; else patt = patt_A5A; err = check_eraseblock(i, patt); if (err) { // printk(PRINT_PREF "verify failed for %s" // " pattern\n", // ((eb + erase_cycles) & 1) ? ; goto out; } cond_resched(); } } erase_cycles += 1; if (erase_cycles % gran == 0) { long ms; stop_timing(); ms = (finish.tv_sec - start.tv_sec) * 1000 + (finish.tv_usec - start.tv_usec) / 1000; // printk(PRINT_PREF "%08u erase cycles done, took %lu " // "milliseconds (%lu seconds)\n", ; start_timing(); } if (!infinite && --cycles_count == 0) break; } out: // printk(PRINT_PREF "finished after %u erase cycles\n", ; kfree(check_buf); out_patt_FF: kfree(patt_FF); out_patt_A5A: kfree(patt_A5A); out_patt_5A5: kfree(patt_5A5); out_mtd: put_mtd_device(mtd); if (err) ; ; return err; }
static int __init dev_nvram_init(void) { int order = 0, ret = 0; struct page *page, *end; unsigned int i; /* Allocate and reserve memory to mmap() */ while ((PAGE_SIZE << order) < NVRAM_SPACE) order++; end = virt_to_page(nvram_buf + (PAGE_SIZE << order) - 1); for (page = virt_to_page(nvram_buf); page <= end; page++) mem_map_reserve(page); #ifdef CONFIG_MTD /* Find associated MTD device */ for (i = 0; i < MAX_MTD_DEVICES; i++) { nvram_mtd = get_mtd_device(NULL, i); if (nvram_mtd) { if (!strcmp(nvram_mtd->name, "nvram") && nvram_mtd->size >= NVRAM_SPACE) break; put_mtd_device(nvram_mtd); } } if (i >= MAX_MTD_DEVICES) nvram_mtd = NULL; #endif /* Initialize hash table lock */ spin_lock_init(&nvram_lock); /* Initialize commit semaphore */ init_MUTEX(&nvram_sem); /* Register char device */ if ((nvram_major = devfs_register_chrdev(0, "nvram", &dev_nvram_fops)) < 0) { ret = nvram_major; goto err; } /* Initialize hash table */ _nvram_init(sbh); /* Create /dev/nvram handle */ nvram_handle = devfs_register(NULL, "nvram", DEVFS_FL_NONE, nvram_major, 0, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, &dev_nvram_fops, NULL); /* Set the SDRAM NCDL value into NVRAM if not already done */ if (getintvar(NULL, "sdram_ncdl") == 0) { unsigned int ncdl; char buf[] = "0x00000000"; if ((ncdl = sb_memc_get_ncdl(sbh))) { sprintf(buf, "0x%08x", ncdl); nvram_set("sdram_ncdl", buf); nvram_commit(); } } return 0; err: dev_nvram_exit(); return ret; }
static int __init mtd_speedtest_init(void) { int err, i, blocks, j, k; long speed; uint64_t tmp; printk(KERN_INFO "\n"); printk(KERN_INFO "=================================================\n"); if (dev < 0) { printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n"); printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n"); return -EINVAL; } if (count) printk(PRINT_PREF "MTD device: %d count: %d\n", dev, count); else printk(PRINT_PREF "MTD device: %d\n", dev); mtd = get_mtd_device(NULL, dev); if (IS_ERR(mtd)) { err = PTR_ERR(mtd); printk(PRINT_PREF "error: cannot get MTD device\n"); return err; } if (mtd->writesize == 1) { printk(PRINT_PREF "not NAND flash, assume page size is 512 " "bytes.\n"); pgsize = 512; } else pgsize = mtd->writesize; tmp = mtd->size; do_div(tmp, mtd->erasesize); ebcnt = tmp; pgcnt = mtd->erasesize / pgsize; printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " "page size %u, count of eraseblocks %u, pages per " "eraseblock %u, OOB size %u\n", (unsigned long long)mtd->size, mtd->erasesize, pgsize, ebcnt, pgcnt, mtd->oobsize); if (count > 0 && count < ebcnt) ebcnt = count; err = -ENOMEM; iobuf = kmalloc(mtd->erasesize, GFP_KERNEL); if (!iobuf) { printk(PRINT_PREF "error: cannot allocate memory\n"); goto out; } simple_srand(1); set_random_data(iobuf, mtd->erasesize); err = scan_for_bad_eraseblocks(); if (err) goto out; err = erase_whole_device(); if (err) goto out; /* Write all eraseblocks, 1 eraseblock at a time */ printk(PRINT_PREF "testing eraseblock write speed\n"); start_timing(); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; err = write_eraseblock(i); if (err) goto out; cond_resched(); } stop_timing(); speed = calc_speed(); printk(PRINT_PREF "eraseblock write speed is %ld KiB/s\n", speed); /* Read all eraseblocks, 1 eraseblock at a time */ printk(PRINT_PREF "testing eraseblock read speed\n"); start_timing(); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; err = read_eraseblock(i); if (err) goto out; cond_resched(); } stop_timing(); speed = calc_speed(); printk(PRINT_PREF "eraseblock read speed is %ld KiB/s\n", speed); err = erase_whole_device(); if (err) goto out; /* Write all eraseblocks, 1 page at a time */ printk(PRINT_PREF "testing page write speed\n"); start_timing(); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; err = write_eraseblock_by_page(i); if (err) goto out; cond_resched(); } stop_timing(); speed = calc_speed(); printk(PRINT_PREF "page write speed is %ld KiB/s\n", speed); /* Read all eraseblocks, 1 page at a time */ printk(PRINT_PREF "testing page read speed\n"); start_timing(); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; err = read_eraseblock_by_page(i); if (err) goto out; cond_resched(); } stop_timing(); speed = calc_speed(); printk(PRINT_PREF "page read speed is %ld KiB/s\n", speed); err = erase_whole_device(); if (err) goto out; /* Write all eraseblocks, 2 pages at a time */ printk(PRINT_PREF "testing 2 page write speed\n"); start_timing(); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; err = write_eraseblock_by_2pages(i); if (err) goto out; cond_resched(); } stop_timing(); speed = calc_speed(); printk(PRINT_PREF "2 page write speed is %ld KiB/s\n", speed); /* Read all eraseblocks, 2 pages at a time */ printk(PRINT_PREF "testing 2 page read speed\n"); start_timing(); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; err = read_eraseblock_by_2pages(i); if (err) goto out; cond_resched(); } stop_timing(); speed = calc_speed(); printk(PRINT_PREF "2 page read speed is %ld KiB/s\n", speed); /* Erase all eraseblocks */ printk(PRINT_PREF "Testing erase speed\n"); start_timing(); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; err = erase_eraseblock(i); if (err) goto out; cond_resched(); } stop_timing(); speed = calc_speed(); printk(PRINT_PREF "erase speed is %ld KiB/s\n", speed); /* Multi-block erase all eraseblocks */ for (k = 1; k < 7; k++) { blocks = 1 << k; printk(PRINT_PREF "Testing %dx multi-block erase speed\n", blocks); start_timing(); for (i = 0; i < ebcnt; ) { for (j = 0; j < blocks && (i + j) < ebcnt; j++) if (bbt[i + j]) break; if (j < 1) { i++; continue; } err = multiblock_erase(i, j); if (err) goto out; cond_resched(); i += j; } stop_timing(); speed = calc_speed(); printk(PRINT_PREF "%dx multi-block erase speed is %ld KiB/s\n", blocks, speed); } printk(PRINT_PREF "finished\n"); out: kfree(iobuf); kfree(bbt); put_mtd_device(mtd); if (err) printk(PRINT_PREF "error %d occurred\n", err); printk(KERN_INFO "=================================================\n"); return err; }
static int dev_nvram_init(void) { int order = 0, ret = 0; struct page *page, *end; unsigned int i; osl_t *osh; /* Allocate and reserve memory to mmap() */ while ((PAGE_SIZE << order) < NVRAM_SPACE) order++; end = virt_to_page(nvram_buf + (PAGE_SIZE << order) - 1); for (page = virt_to_page(nvram_buf); page <= end; page++) { SetPageReserved(page); } #if defined(CONFIG_MTD) || defined(CONFIG_MTD_MODULE) /* Find associated MTD device */ for (i = 0; i < MAX_MTD_DEVICES; i++) { nvram_mtd = get_mtd_device(NULL, i); if (!IS_ERR(nvram_mtd)) { if (!strcmp(nvram_mtd->name, "nvram") && nvram_mtd->size >= NVRAM_SPACE) { break; } put_mtd_device(nvram_mtd); } } if (i >= MAX_MTD_DEVICES) nvram_mtd = NULL; #endif #ifdef RTN66U_NVRAM_64K_SUPPORT int ret32; char *log_buf; u_int32_t offset_t; size_t log_len; DECLARE_WAITQUEUE(wait, current); wait_queue_head_t wait_q; struct erase_info erase; offset_t = 0x18000; ret32 = nvram_mtd->read(nvram_mtd, offset_t, 4, &log_len, &log_buf); if(log_buf==0xffffffff) { /* Erase sector blocks */ init_waitqueue_head(&wait_q); erase.mtd = nvram_mtd; erase.addr = 0; erase.len = nvram_mtd->erasesize; erase.callback = erase_callback; erase.priv = (u_long) &wait_q; set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&wait_q, &wait); /* Unlock sector blocks */ if (nvram_mtd->unlock) nvram_mtd->unlock(nvram_mtd, 0, nvram_mtd->erasesize); if ((ret = nvram_mtd->erase(nvram_mtd, &erase))) { set_current_state(TASK_RUNNING); remove_wait_queue(&wait_q, &wait); printk("nvram mtd erase error\n"); } /* Wait for erase to finish */ schedule(); remove_wait_queue(&wait_q, &wait); } #endif /* Initialize hash table lock */ spin_lock_init(&nvram_lock); /* Initialize commit semaphore */ init_MUTEX(&nvram_sem); /* Register char device */ if ((nvram_major = register_chrdev(0, "nvram", &dev_nvram_fops)) < 0) { ret = nvram_major; goto err; } if (si_osh(sih) == NULL) { osh = osl_attach(NULL, SI_BUS, FALSE); if (osh == NULL) { printk("Error allocating osh\n"); unregister_chrdev(nvram_major, "nvram"); goto err; } si_setosh(sih, osh); } /* Initialize hash table */ _nvram_init(sih); /* Create /dev/nvram handle */ nvram_class = class_create(THIS_MODULE, "nvram"); if (IS_ERR(nvram_class)) { printk("Error creating nvram class\n"); goto err; } /* Add the device nvram0 */ class_device_create(nvram_class, NULL, MKDEV(nvram_major, 0), NULL, "nvram"); /* reserve commit read buffer */ /* Backup sector blocks to be erased */ if (!(nvram_commit_buf = kmalloc(ROUNDUP(NVRAM_SPACE, nvram_mtd->erasesize), GFP_KERNEL))) { printk("dev_nvram_init: nvram_commit_buf out of memory\n"); goto err; } /* Set the SDRAM NCDL value into NVRAM if not already done */ if (getintvar(NULL, "sdram_ncdl") == 0) { unsigned int ncdl; char buf[] = "0x00000000"; if ((ncdl = si_memc_get_ncdl(sih))) { sprintf(buf, "0x%08x", ncdl); nvram_set("sdram_ncdl", buf); nvram_commit(); } } return 0; err: dev_nvram_exit(); return ret; }