예제 #1
0
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 */
예제 #2
0
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;
}
예제 #3
0
파일: gpio.c 프로젝트: celeduc/TL-WR703N
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;

}
예제 #4
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
예제 #7
0
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;
}
예제 #8
0
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;
}
예제 #9
0
파일: jffs_fm.c 프로젝트: NieHao/Tomato-RAF
/* 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;
}
예제 #10
0
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;
}
예제 #11
0
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;
}
예제 #12
0
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;
}
예제 #13
0
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;
}
예제 #14
0
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;
}
예제 #15
0
파일: oobtest.c 프로젝트: 3null/linux
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;
}
예제 #16
0
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;
}
예제 #17
0
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;
}
예제 #18
0
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;
}
예제 #19
0
/*
 * 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;
}
예제 #20
0
파일: readtest.c 프로젝트: 020gzh/linux
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;
}
예제 #21
0
파일: axfs_super.c 프로젝트: kmaddock/axfs
/******************************************************************************
 *
 * 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);
}
예제 #22
0
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;
}
예제 #23
0
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;
}
예제 #24
0
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;
}
예제 #25
0
파일: cdev.c 프로젝트: maraz/linux-2.6
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;
}
예제 #26
0
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;
}
예제 #27
0
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;
}
예제 #28
0
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;
}
예제 #30
0
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;
}