brintos

brintos / linux-shallow public Read only

0
0
Text · 4.4 KiB · 99670ef Raw
216 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2006-2008 Nokia Corporation4 *5 * Check MTD device read.6 *7 * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>8 */9 10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt11 12#include <linux/init.h>13#include <linux/module.h>14#include <linux/moduleparam.h>15#include <linux/err.h>16#include <linux/mtd/mtd.h>17#include <linux/slab.h>18#include <linux/sched.h>19 20#include "mtd_test.h"21 22static int dev = -EINVAL;23module_param(dev, int, S_IRUGO);24MODULE_PARM_DESC(dev, "MTD device number to use");25 26static struct mtd_info *mtd;27static unsigned char *iobuf;28static unsigned char *iobuf1;29static unsigned char *bbt;30 31static int pgsize;32static int ebcnt;33static int pgcnt;34 35static int read_eraseblock_by_page(int ebnum)36{37	int i, ret, err = 0;38	loff_t addr = (loff_t)ebnum * mtd->erasesize;39	void *buf = iobuf;40	void *oobbuf = iobuf1;41 42	for (i = 0; i < pgcnt; i++) {43		memset(buf, 0 , pgsize);44		ret = mtdtest_read(mtd, addr, pgsize, buf);45		if (ret) {46			if (!err)47				err = ret;48		}49		if (mtd->oobsize) {50			struct mtd_oob_ops ops = { };51 52			ops.mode      = MTD_OPS_PLACE_OOB;53			ops.len       = 0;54			ops.retlen    = 0;55			ops.ooblen    = mtd->oobsize;56			ops.oobretlen = 0;57			ops.ooboffs   = 0;58			ops.datbuf    = NULL;59			ops.oobbuf    = oobbuf;60			ret = mtd_read_oob(mtd, addr, &ops);61			if ((ret && !mtd_is_bitflip(ret)) ||62					ops.oobretlen != mtd->oobsize) {63				pr_err("error: read oob failed at "64						  "%#llx\n", (long long)addr);65				if (!err)66					err = ret;67				if (!err)68					err = -EINVAL;69			}70			oobbuf += mtd->oobsize;71		}72		addr += pgsize;73		buf += pgsize;74	}75 76	return err;77}78 79static void dump_eraseblock(int ebnum)80{81	int i, j, n;82	char line[128];83	int pg, oob;84 85	pr_info("dumping eraseblock %d\n", ebnum);86	n = mtd->erasesize;87	for (i = 0; i < n;) {88		char *p = line;89 90		p += sprintf(p, "%05x: ", i);91		for (j = 0; j < 32 && i < n; j++, i++)92			p += sprintf(p, "%02x", (unsigned int)iobuf[i]);93		printk(KERN_CRIT "%s\n", line);94		cond_resched();95	}96	if (!mtd->oobsize)97		return;98	pr_info("dumping oob from eraseblock %d\n", ebnum);99	n = mtd->oobsize;100	for (pg = 0, i = 0; pg < pgcnt; pg++)101		for (oob = 0; oob < n;) {102			char *p = line;103 104			p += sprintf(p, "%05x: ", i);105			for (j = 0; j < 32 && oob < n; j++, oob++, i++)106				p += sprintf(p, "%02x",107					     (unsigned int)iobuf1[i]);108			printk(KERN_CRIT "%s\n", line);109			cond_resched();110		}111}112 113static int __init mtd_readtest_init(void)114{115	uint64_t tmp;116	int err, i;117 118	printk(KERN_INFO "\n");119	printk(KERN_INFO "=================================================\n");120 121	if (dev < 0) {122		pr_info("Please specify a valid mtd-device via module parameter\n");123		return -EINVAL;124	}125 126	pr_info("MTD device: %d\n", dev);127 128	mtd = get_mtd_device(NULL, dev);129	if (IS_ERR(mtd)) {130		err = PTR_ERR(mtd);131		pr_err("error: Cannot get MTD device\n");132		return err;133	}134 135	if (mtd->writesize == 1) {136		pr_info("not NAND flash, assume page size is 512 "137		       "bytes.\n");138		pgsize = 512;139	} else140		pgsize = mtd->writesize;141 142	tmp = mtd->size;143	do_div(tmp, mtd->erasesize);144	ebcnt = tmp;145	pgcnt = mtd->erasesize / pgsize;146 147	pr_info("MTD device size %llu, eraseblock size %u, "148	       "page size %u, count of eraseblocks %u, pages per "149	       "eraseblock %u, OOB size %u\n",150	       (unsigned long long)mtd->size, mtd->erasesize,151	       pgsize, ebcnt, pgcnt, mtd->oobsize);152 153	err = -ENOMEM;154	iobuf = kmalloc(mtd->erasesize, GFP_KERNEL);155	if (!iobuf)156		goto out;157	iobuf1 = kmalloc(mtd->erasesize, GFP_KERNEL);158	if (!iobuf1)159		goto out;160 161	bbt = kzalloc(ebcnt, GFP_KERNEL);162	if (!bbt)163		goto out;164	err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);165	if (err)166		goto out;167 168	/* Read all eraseblocks 1 page at a time */169	pr_info("testing page read\n");170	for (i = 0; i < ebcnt; ++i) {171		int ret;172 173		if (bbt[i])174			continue;175		ret = read_eraseblock_by_page(i);176		if (ret) {177			dump_eraseblock(i);178			if (!err)179				err = ret;180		}181 182		ret = mtdtest_relax();183		if (ret) {184			err = ret;185			goto out;186		}187	}188 189	if (err)190		pr_info("finished with errors\n");191	else192		pr_info("finished\n");193 194out:195 196	kfree(iobuf);197	kfree(iobuf1);198	kfree(bbt);199	put_mtd_device(mtd);200	if (err)201		pr_info("error %d occurred\n", err);202	printk(KERN_INFO "=================================================\n");203	return err;204}205module_init(mtd_readtest_init);206 207static void __exit mtd_readtest_exit(void)208{209	return;210}211module_exit(mtd_readtest_exit);212 213MODULE_DESCRIPTION("Read test module");214MODULE_AUTHOR("Adrian Hunter");215MODULE_LICENSE("GPL");216