blob: b679a7c45a1eb716ab2827b8cfc868bc1f718047 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/*
2 * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
3 * Copyright (C) 2006-2008 Nokia Corporation
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published by
7 * the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; see the file COPYING. If not, write to the Free Software
16 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 *
18 * Erase the given MTD partition.
19 *
20 */
21
22#include <asm/div64.h>
23#include <linux/init.h>
24#include <linux/module.h>
25#include <linux/moduleparam.h>
26#include <linux/err.h>
27#include <linux/mtd/mtd.h>
28#include <linux/sched.h>
29#include <linux/slab.h>
30
31#define PRINT_PREF KERN_INFO "mtd_erasepart: "
32
33static int dev;
34module_param(dev, int, S_IRUGO);
35MODULE_PARM_DESC(dev, "MTD device number to use");
36
37static struct mtd_info *mtd;
38static unsigned char *bbt;
39static int ebcnt;
40
41static int erase_eraseblock(int ebnum)
42{
43 int err;
44 struct erase_info ei;
45 loff_t addr = ebnum * mtd->erasesize;
46
47 memset(&ei, 0, sizeof(struct erase_info));
48 ei.mtd = mtd;
49 ei.addr = addr;
50 ei.len = mtd->erasesize;
51
52 err = mtd->erase(mtd, &ei);
53 if (err) {
54 printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
55 return err;
56 }
57
58 if (ei.state == MTD_ERASE_FAILED) {
59 printk(PRINT_PREF "some erase error occurred at EB %d\n",
60 ebnum);
61 return -EIO;
62 }
63
64 return 0;
65}
66
67static int erase_whole_device(void)
68{
69 int err;
70 unsigned int i;
71
72 printk(PRINT_PREF "erasing whole device\n");
73 for (i = 0; i < ebcnt; ++i) {
74 if (bbt[i])
75 continue;
76 err = erase_eraseblock(i);
77 if (err)
78 return err;
79 cond_resched();
80 }
81 printk(PRINT_PREF "erased %u eraseblocks\n", i);
82 return 0;
83}
84
85static int is_block_bad(int ebnum)
86{
87 int ret;
88 loff_t addr = ebnum * mtd->erasesize;
89
90 ret = mtd->block_isbad(mtd, addr);
91 if (ret)
92 printk(PRINT_PREF "block %d is bad\n", ebnum);
93 return ret;
94}
95
96static int scan_for_bad_eraseblocks(void)
97{
98 int i, bad = 0;
99
100 bbt = kmalloc(ebcnt, GFP_KERNEL);
101 if (!bbt) {
102 printk(PRINT_PREF "error: cannot allocate memory\n");
103 return -ENOMEM;
104 }
105 memset(bbt, 0 , ebcnt);
106
107 printk(PRINT_PREF "scanning for bad eraseblocks\n");
108 for (i = 0; i < ebcnt; ++i) {
109 bbt[i] = is_block_bad(i) ? 1 : 0;
110 if (bbt[i])
111 bad += 1;
112 cond_resched();
113 }
114 printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
115 return 0;
116}
117
118static int __init mtd_erasepart_init(void)
119{
120 int err = 0;
121 uint64_t tmp;
122
123 printk(KERN_INFO "\n");
124 printk(KERN_INFO "=================================================\n");
125 printk(PRINT_PREF "MTD device: %d\n", dev);
126
127 mtd = get_mtd_device(NULL, dev);
128 if (IS_ERR(mtd)) {
129 err = PTR_ERR(mtd);
130 printk(PRINT_PREF "error: cannot get MTD device\n");
131 return err;
132 }
133
134 if (mtd->type != MTD_NANDFLASH) {
135 printk(PRINT_PREF "this test requires NAND flash\n");
136 err = -ENODEV;
137 goto out2;
138 }
139
140 tmp = mtd->size;
141 do_div(tmp, mtd->erasesize);
142 ebcnt = tmp;
143
144 printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
145 "page size %u, count of eraseblocks %u",
146 (unsigned long long)mtd->size, mtd->erasesize,
147 mtd->writesize, ebcnt);
148
149 err = scan_for_bad_eraseblocks();
150 if (err)
151 goto out1;
152
153 printk(PRINT_PREF "Erasing the whole mtd partition\n");
154
155 err = erase_whole_device();
156out1:
157 kfree(bbt);
158out2:
159 put_mtd_device(mtd);
160 if (err)
161 printk(PRINT_PREF "error %d occurred\n", err);
162 printk(KERN_INFO "=================================================\n");
163 return err;
164}
165module_init(mtd_erasepart_init);
166
167static void __exit mtd_erasepart_exit(void)
168{
169 return;
170}
171module_exit(mtd_erasepart_exit);
172
173MODULE_DESCRIPTION("Erase a given MTD partition");
174MODULE_LICENSE("GPL v2");