xref: /rk3399_rockchip-uboot/drivers/mtd/mtdpart.c (revision e29c22f5abe6e0f4baa6251efed6074cdfc3db79)
1*e29c22f5SKyungmin Park /*
2*e29c22f5SKyungmin Park  * Simple MTD partitioning layer
3*e29c22f5SKyungmin Park  *
4*e29c22f5SKyungmin Park  * (C) 2000 Nicolas Pitre <nico@cam.org>
5*e29c22f5SKyungmin Park  *
6*e29c22f5SKyungmin Park  * This code is GPL
7*e29c22f5SKyungmin Park  *
8*e29c22f5SKyungmin Park  * 	02-21-2002	Thomas Gleixner <gleixner@autronix.de>
9*e29c22f5SKyungmin Park  *			added support for read_oob, write_oob
10*e29c22f5SKyungmin Park  */
11*e29c22f5SKyungmin Park 
12*e29c22f5SKyungmin Park #include <common.h>
13*e29c22f5SKyungmin Park #include <malloc.h>
14*e29c22f5SKyungmin Park #include <asm/errno.h>
15*e29c22f5SKyungmin Park 
16*e29c22f5SKyungmin Park #include <linux/types.h>
17*e29c22f5SKyungmin Park #include <linux/list.h>
18*e29c22f5SKyungmin Park #include <linux/mtd/mtd.h>
19*e29c22f5SKyungmin Park #include <linux/mtd/partitions.h>
20*e29c22f5SKyungmin Park #include <linux/mtd/compat.h>
21*e29c22f5SKyungmin Park 
22*e29c22f5SKyungmin Park /* Our partition linked list */
23*e29c22f5SKyungmin Park static LIST_HEAD(mtd_partitions);
24*e29c22f5SKyungmin Park 
25*e29c22f5SKyungmin Park /* Our partition node structure */
26*e29c22f5SKyungmin Park struct mtd_part {
27*e29c22f5SKyungmin Park 	struct mtd_info mtd;
28*e29c22f5SKyungmin Park 	struct mtd_info *master;
29*e29c22f5SKyungmin Park 	u_int32_t offset;
30*e29c22f5SKyungmin Park 	int index;
31*e29c22f5SKyungmin Park 	struct list_head list;
32*e29c22f5SKyungmin Park 	int registered;
33*e29c22f5SKyungmin Park };
34*e29c22f5SKyungmin Park 
35*e29c22f5SKyungmin Park /*
36*e29c22f5SKyungmin Park  * Given a pointer to the MTD object in the mtd_part structure, we can retrieve
37*e29c22f5SKyungmin Park  * the pointer to that structure with this macro.
38*e29c22f5SKyungmin Park  */
39*e29c22f5SKyungmin Park #define PART(x)  ((struct mtd_part *)(x))
40*e29c22f5SKyungmin Park 
41*e29c22f5SKyungmin Park 
42*e29c22f5SKyungmin Park /*
43*e29c22f5SKyungmin Park  * MTD methods which simply translate the effective address and pass through
44*e29c22f5SKyungmin Park  * to the _real_ device.
45*e29c22f5SKyungmin Park  */
46*e29c22f5SKyungmin Park 
47*e29c22f5SKyungmin Park static int part_read (struct mtd_info *mtd, loff_t from, size_t len,
48*e29c22f5SKyungmin Park 			size_t *retlen, u_char *buf)
49*e29c22f5SKyungmin Park {
50*e29c22f5SKyungmin Park 	struct mtd_part *part = PART(mtd);
51*e29c22f5SKyungmin Park 	int res;
52*e29c22f5SKyungmin Park 
53*e29c22f5SKyungmin Park 	if (from >= mtd->size)
54*e29c22f5SKyungmin Park 		len = 0;
55*e29c22f5SKyungmin Park 	else if (from + len > mtd->size)
56*e29c22f5SKyungmin Park 		len = mtd->size - from;
57*e29c22f5SKyungmin Park 	res = part->master->read (part->master, from + part->offset,
58*e29c22f5SKyungmin Park 				   len, retlen, buf);
59*e29c22f5SKyungmin Park 	if (unlikely(res)) {
60*e29c22f5SKyungmin Park 		if (res == -EUCLEAN)
61*e29c22f5SKyungmin Park 			mtd->ecc_stats.corrected++;
62*e29c22f5SKyungmin Park 		if (res == -EBADMSG)
63*e29c22f5SKyungmin Park 			mtd->ecc_stats.failed++;
64*e29c22f5SKyungmin Park 	}
65*e29c22f5SKyungmin Park 	return res;
66*e29c22f5SKyungmin Park }
67*e29c22f5SKyungmin Park 
68*e29c22f5SKyungmin Park #ifdef MTD_LINUX
69*e29c22f5SKyungmin Park static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
70*e29c22f5SKyungmin Park 			size_t *retlen, void **virt, resource_size_t *phys)
71*e29c22f5SKyungmin Park {
72*e29c22f5SKyungmin Park 	struct mtd_part *part = PART(mtd);
73*e29c22f5SKyungmin Park 	if (from >= mtd->size)
74*e29c22f5SKyungmin Park 		len = 0;
75*e29c22f5SKyungmin Park 	else if (from + len > mtd->size)
76*e29c22f5SKyungmin Park 		len = mtd->size - from;
77*e29c22f5SKyungmin Park 	return part->master->point (part->master, from + part->offset,
78*e29c22f5SKyungmin Park 				    len, retlen, virt, phys);
79*e29c22f5SKyungmin Park }
80*e29c22f5SKyungmin Park 
81*e29c22f5SKyungmin Park static void part_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
82*e29c22f5SKyungmin Park {
83*e29c22f5SKyungmin Park 	struct mtd_part *part = PART(mtd);
84*e29c22f5SKyungmin Park 
85*e29c22f5SKyungmin Park 	part->master->unpoint(part->master, from + part->offset, len);
86*e29c22f5SKyungmin Park }
87*e29c22f5SKyungmin Park #endif
88*e29c22f5SKyungmin Park 
89*e29c22f5SKyungmin Park static int part_read_oob(struct mtd_info *mtd, loff_t from,
90*e29c22f5SKyungmin Park 			 struct mtd_oob_ops *ops)
91*e29c22f5SKyungmin Park {
92*e29c22f5SKyungmin Park 	struct mtd_part *part = PART(mtd);
93*e29c22f5SKyungmin Park 	int res;
94*e29c22f5SKyungmin Park 
95*e29c22f5SKyungmin Park 	if (from >= mtd->size)
96*e29c22f5SKyungmin Park 		return -EINVAL;
97*e29c22f5SKyungmin Park 	if (ops->datbuf && from + ops->len > mtd->size)
98*e29c22f5SKyungmin Park 		return -EINVAL;
99*e29c22f5SKyungmin Park 	res = part->master->read_oob(part->master, from + part->offset, ops);
100*e29c22f5SKyungmin Park 
101*e29c22f5SKyungmin Park 	if (unlikely(res)) {
102*e29c22f5SKyungmin Park 		if (res == -EUCLEAN)
103*e29c22f5SKyungmin Park 			mtd->ecc_stats.corrected++;
104*e29c22f5SKyungmin Park 		if (res == -EBADMSG)
105*e29c22f5SKyungmin Park 			mtd->ecc_stats.failed++;
106*e29c22f5SKyungmin Park 	}
107*e29c22f5SKyungmin Park 	return res;
108*e29c22f5SKyungmin Park }
109*e29c22f5SKyungmin Park 
110*e29c22f5SKyungmin Park static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len,
111*e29c22f5SKyungmin Park 			size_t *retlen, u_char *buf)
112*e29c22f5SKyungmin Park {
113*e29c22f5SKyungmin Park 	struct mtd_part *part = PART(mtd);
114*e29c22f5SKyungmin Park 	return part->master->read_user_prot_reg (part->master, from,
115*e29c22f5SKyungmin Park 					len, retlen, buf);
116*e29c22f5SKyungmin Park }
117*e29c22f5SKyungmin Park 
118*e29c22f5SKyungmin Park static int part_get_user_prot_info (struct mtd_info *mtd,
119*e29c22f5SKyungmin Park 				    struct otp_info *buf, size_t len)
120*e29c22f5SKyungmin Park {
121*e29c22f5SKyungmin Park 	struct mtd_part *part = PART(mtd);
122*e29c22f5SKyungmin Park 	return part->master->get_user_prot_info (part->master, buf, len);
123*e29c22f5SKyungmin Park }
124*e29c22f5SKyungmin Park 
125*e29c22f5SKyungmin Park static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len,
126*e29c22f5SKyungmin Park 			size_t *retlen, u_char *buf)
127*e29c22f5SKyungmin Park {
128*e29c22f5SKyungmin Park 	struct mtd_part *part = PART(mtd);
129*e29c22f5SKyungmin Park 	return part->master->read_fact_prot_reg (part->master, from,
130*e29c22f5SKyungmin Park 					len, retlen, buf);
131*e29c22f5SKyungmin Park }
132*e29c22f5SKyungmin Park 
133*e29c22f5SKyungmin Park static int part_get_fact_prot_info (struct mtd_info *mtd,
134*e29c22f5SKyungmin Park 				    struct otp_info *buf, size_t len)
135*e29c22f5SKyungmin Park {
136*e29c22f5SKyungmin Park 	struct mtd_part *part = PART(mtd);
137*e29c22f5SKyungmin Park 	return part->master->get_fact_prot_info (part->master, buf, len);
138*e29c22f5SKyungmin Park }
139*e29c22f5SKyungmin Park 
140*e29c22f5SKyungmin Park static int part_write (struct mtd_info *mtd, loff_t to, size_t len,
141*e29c22f5SKyungmin Park 			size_t *retlen, const u_char *buf)
142*e29c22f5SKyungmin Park {
143*e29c22f5SKyungmin Park 	struct mtd_part *part = PART(mtd);
144*e29c22f5SKyungmin Park 	if (!(mtd->flags & MTD_WRITEABLE))
145*e29c22f5SKyungmin Park 		return -EROFS;
146*e29c22f5SKyungmin Park 	if (to >= mtd->size)
147*e29c22f5SKyungmin Park 		len = 0;
148*e29c22f5SKyungmin Park 	else if (to + len > mtd->size)
149*e29c22f5SKyungmin Park 		len = mtd->size - to;
150*e29c22f5SKyungmin Park 	return part->master->write (part->master, to + part->offset,
151*e29c22f5SKyungmin Park 				    len, retlen, buf);
152*e29c22f5SKyungmin Park }
153*e29c22f5SKyungmin Park 
154*e29c22f5SKyungmin Park #ifdef MTD_LINUX
155*e29c22f5SKyungmin Park static int part_panic_write (struct mtd_info *mtd, loff_t to, size_t len,
156*e29c22f5SKyungmin Park 			size_t *retlen, const u_char *buf)
157*e29c22f5SKyungmin Park {
158*e29c22f5SKyungmin Park 	struct mtd_part *part = PART(mtd);
159*e29c22f5SKyungmin Park 	if (!(mtd->flags & MTD_WRITEABLE))
160*e29c22f5SKyungmin Park 		return -EROFS;
161*e29c22f5SKyungmin Park 	if (to >= mtd->size)
162*e29c22f5SKyungmin Park 		len = 0;
163*e29c22f5SKyungmin Park 	else if (to + len > mtd->size)
164*e29c22f5SKyungmin Park 		len = mtd->size - to;
165*e29c22f5SKyungmin Park 	return part->master->panic_write (part->master, to + part->offset,
166*e29c22f5SKyungmin Park 				    len, retlen, buf);
167*e29c22f5SKyungmin Park }
168*e29c22f5SKyungmin Park #endif
169*e29c22f5SKyungmin Park 
170*e29c22f5SKyungmin Park static int part_write_oob(struct mtd_info *mtd, loff_t to,
171*e29c22f5SKyungmin Park 			 struct mtd_oob_ops *ops)
172*e29c22f5SKyungmin Park {
173*e29c22f5SKyungmin Park 	struct mtd_part *part = PART(mtd);
174*e29c22f5SKyungmin Park 
175*e29c22f5SKyungmin Park 	if (!(mtd->flags & MTD_WRITEABLE))
176*e29c22f5SKyungmin Park 		return -EROFS;
177*e29c22f5SKyungmin Park 
178*e29c22f5SKyungmin Park 	if (to >= mtd->size)
179*e29c22f5SKyungmin Park 		return -EINVAL;
180*e29c22f5SKyungmin Park 	if (ops->datbuf && to + ops->len > mtd->size)
181*e29c22f5SKyungmin Park 		return -EINVAL;
182*e29c22f5SKyungmin Park 	return part->master->write_oob(part->master, to + part->offset, ops);
183*e29c22f5SKyungmin Park }
184*e29c22f5SKyungmin Park 
185*e29c22f5SKyungmin Park static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len,
186*e29c22f5SKyungmin Park 			size_t *retlen, u_char *buf)
187*e29c22f5SKyungmin Park {
188*e29c22f5SKyungmin Park 	struct mtd_part *part = PART(mtd);
189*e29c22f5SKyungmin Park 	return part->master->write_user_prot_reg (part->master, from,
190*e29c22f5SKyungmin Park 					len, retlen, buf);
191*e29c22f5SKyungmin Park }
192*e29c22f5SKyungmin Park 
193*e29c22f5SKyungmin Park static int part_lock_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len)
194*e29c22f5SKyungmin Park {
195*e29c22f5SKyungmin Park 	struct mtd_part *part = PART(mtd);
196*e29c22f5SKyungmin Park 	return part->master->lock_user_prot_reg (part->master, from, len);
197*e29c22f5SKyungmin Park }
198*e29c22f5SKyungmin Park 
199*e29c22f5SKyungmin Park #ifdef MTD_LINUX
200*e29c22f5SKyungmin Park static int part_writev (struct mtd_info *mtd,  const struct kvec *vecs,
201*e29c22f5SKyungmin Park 			 unsigned long count, loff_t to, size_t *retlen)
202*e29c22f5SKyungmin Park {
203*e29c22f5SKyungmin Park 	struct mtd_part *part = PART(mtd);
204*e29c22f5SKyungmin Park 	if (!(mtd->flags & MTD_WRITEABLE))
205*e29c22f5SKyungmin Park 		return -EROFS;
206*e29c22f5SKyungmin Park 	return part->master->writev (part->master, vecs, count,
207*e29c22f5SKyungmin Park 					to + part->offset, retlen);
208*e29c22f5SKyungmin Park }
209*e29c22f5SKyungmin Park #endif
210*e29c22f5SKyungmin Park 
211*e29c22f5SKyungmin Park static int part_erase (struct mtd_info *mtd, struct erase_info *instr)
212*e29c22f5SKyungmin Park {
213*e29c22f5SKyungmin Park 	struct mtd_part *part = PART(mtd);
214*e29c22f5SKyungmin Park 	int ret;
215*e29c22f5SKyungmin Park 	if (!(mtd->flags & MTD_WRITEABLE))
216*e29c22f5SKyungmin Park 		return -EROFS;
217*e29c22f5SKyungmin Park 	if (instr->addr >= mtd->size)
218*e29c22f5SKyungmin Park 		return -EINVAL;
219*e29c22f5SKyungmin Park 	instr->addr += part->offset;
220*e29c22f5SKyungmin Park 	ret = part->master->erase(part->master, instr);
221*e29c22f5SKyungmin Park 	if (ret) {
222*e29c22f5SKyungmin Park 		if (instr->fail_addr != 0xffffffff)
223*e29c22f5SKyungmin Park 			instr->fail_addr -= part->offset;
224*e29c22f5SKyungmin Park 		instr->addr -= part->offset;
225*e29c22f5SKyungmin Park 	}
226*e29c22f5SKyungmin Park 	return ret;
227*e29c22f5SKyungmin Park }
228*e29c22f5SKyungmin Park 
229*e29c22f5SKyungmin Park void mtd_erase_callback(struct erase_info *instr)
230*e29c22f5SKyungmin Park {
231*e29c22f5SKyungmin Park 	if (instr->mtd->erase == part_erase) {
232*e29c22f5SKyungmin Park 		struct mtd_part *part = PART(instr->mtd);
233*e29c22f5SKyungmin Park 
234*e29c22f5SKyungmin Park 		if (instr->fail_addr != 0xffffffff)
235*e29c22f5SKyungmin Park 			instr->fail_addr -= part->offset;
236*e29c22f5SKyungmin Park 		instr->addr -= part->offset;
237*e29c22f5SKyungmin Park 	}
238*e29c22f5SKyungmin Park 	if (instr->callback)
239*e29c22f5SKyungmin Park 		instr->callback(instr);
240*e29c22f5SKyungmin Park }
241*e29c22f5SKyungmin Park #ifdef MTD_LINUX
242*e29c22f5SKyungmin Park EXPORT_SYMBOL_GPL(mtd_erase_callback);
243*e29c22f5SKyungmin Park #endif
244*e29c22f5SKyungmin Park 
245*e29c22f5SKyungmin Park #ifdef MTD_LINUX
246*e29c22f5SKyungmin Park static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
247*e29c22f5SKyungmin Park {
248*e29c22f5SKyungmin Park 	struct mtd_part *part = PART(mtd);
249*e29c22f5SKyungmin Park 	if ((len + ofs) > mtd->size)
250*e29c22f5SKyungmin Park 		return -EINVAL;
251*e29c22f5SKyungmin Park 	return part->master->lock(part->master, ofs + part->offset, len);
252*e29c22f5SKyungmin Park }
253*e29c22f5SKyungmin Park 
254*e29c22f5SKyungmin Park static int part_unlock (struct mtd_info *mtd, loff_t ofs, size_t len)
255*e29c22f5SKyungmin Park {
256*e29c22f5SKyungmin Park 	struct mtd_part *part = PART(mtd);
257*e29c22f5SKyungmin Park 	if ((len + ofs) > mtd->size)
258*e29c22f5SKyungmin Park 		return -EINVAL;
259*e29c22f5SKyungmin Park 	return part->master->unlock(part->master, ofs + part->offset, len);
260*e29c22f5SKyungmin Park }
261*e29c22f5SKyungmin Park #endif
262*e29c22f5SKyungmin Park 
263*e29c22f5SKyungmin Park static void part_sync(struct mtd_info *mtd)
264*e29c22f5SKyungmin Park {
265*e29c22f5SKyungmin Park 	struct mtd_part *part = PART(mtd);
266*e29c22f5SKyungmin Park 	part->master->sync(part->master);
267*e29c22f5SKyungmin Park }
268*e29c22f5SKyungmin Park 
269*e29c22f5SKyungmin Park #ifdef MTD_LINUX
270*e29c22f5SKyungmin Park static int part_suspend(struct mtd_info *mtd)
271*e29c22f5SKyungmin Park {
272*e29c22f5SKyungmin Park 	struct mtd_part *part = PART(mtd);
273*e29c22f5SKyungmin Park 	return part->master->suspend(part->master);
274*e29c22f5SKyungmin Park }
275*e29c22f5SKyungmin Park 
276*e29c22f5SKyungmin Park static void part_resume(struct mtd_info *mtd)
277*e29c22f5SKyungmin Park {
278*e29c22f5SKyungmin Park 	struct mtd_part *part = PART(mtd);
279*e29c22f5SKyungmin Park 	part->master->resume(part->master);
280*e29c22f5SKyungmin Park }
281*e29c22f5SKyungmin Park #endif
282*e29c22f5SKyungmin Park 
283*e29c22f5SKyungmin Park static int part_block_isbad (struct mtd_info *mtd, loff_t ofs)
284*e29c22f5SKyungmin Park {
285*e29c22f5SKyungmin Park 	struct mtd_part *part = PART(mtd);
286*e29c22f5SKyungmin Park 	if (ofs >= mtd->size)
287*e29c22f5SKyungmin Park 		return -EINVAL;
288*e29c22f5SKyungmin Park 	ofs += part->offset;
289*e29c22f5SKyungmin Park 	return part->master->block_isbad(part->master, ofs);
290*e29c22f5SKyungmin Park }
291*e29c22f5SKyungmin Park 
292*e29c22f5SKyungmin Park static int part_block_markbad (struct mtd_info *mtd, loff_t ofs)
293*e29c22f5SKyungmin Park {
294*e29c22f5SKyungmin Park 	struct mtd_part *part = PART(mtd);
295*e29c22f5SKyungmin Park 	int res;
296*e29c22f5SKyungmin Park 
297*e29c22f5SKyungmin Park 	if (!(mtd->flags & MTD_WRITEABLE))
298*e29c22f5SKyungmin Park 		return -EROFS;
299*e29c22f5SKyungmin Park 	if (ofs >= mtd->size)
300*e29c22f5SKyungmin Park 		return -EINVAL;
301*e29c22f5SKyungmin Park 	ofs += part->offset;
302*e29c22f5SKyungmin Park 	res = part->master->block_markbad(part->master, ofs);
303*e29c22f5SKyungmin Park #ifdef MTD_LINUX
304*e29c22f5SKyungmin Park 	if (!res)
305*e29c22f5SKyungmin Park 		mtd->ecc_stats.badblocks++;
306*e29c22f5SKyungmin Park #endif
307*e29c22f5SKyungmin Park 	return res;
308*e29c22f5SKyungmin Park }
309*e29c22f5SKyungmin Park 
310*e29c22f5SKyungmin Park /*
311*e29c22f5SKyungmin Park  * This function unregisters and destroy all slave MTD objects which are
312*e29c22f5SKyungmin Park  * attached to the given master MTD object.
313*e29c22f5SKyungmin Park  */
314*e29c22f5SKyungmin Park 
315*e29c22f5SKyungmin Park int del_mtd_partitions(struct mtd_info *master)
316*e29c22f5SKyungmin Park {
317*e29c22f5SKyungmin Park 	struct list_head *node;
318*e29c22f5SKyungmin Park 	struct mtd_part *slave;
319*e29c22f5SKyungmin Park 
320*e29c22f5SKyungmin Park 	for (node = mtd_partitions.next;
321*e29c22f5SKyungmin Park 	     node != &mtd_partitions;
322*e29c22f5SKyungmin Park 	     node = node->next) {
323*e29c22f5SKyungmin Park 		slave = list_entry(node, struct mtd_part, list);
324*e29c22f5SKyungmin Park 		if (slave->master == master) {
325*e29c22f5SKyungmin Park 			struct list_head *prev = node->prev;
326*e29c22f5SKyungmin Park 			__list_del(prev, node->next);
327*e29c22f5SKyungmin Park 			if(slave->registered)
328*e29c22f5SKyungmin Park 				del_mtd_device(&slave->mtd);
329*e29c22f5SKyungmin Park 			kfree(slave);
330*e29c22f5SKyungmin Park 			node = prev;
331*e29c22f5SKyungmin Park 		}
332*e29c22f5SKyungmin Park 	}
333*e29c22f5SKyungmin Park 
334*e29c22f5SKyungmin Park 	return 0;
335*e29c22f5SKyungmin Park }
336*e29c22f5SKyungmin Park 
337*e29c22f5SKyungmin Park /*
338*e29c22f5SKyungmin Park  * This function, given a master MTD object and a partition table, creates
339*e29c22f5SKyungmin Park  * and registers slave MTD objects which are bound to the master according to
340*e29c22f5SKyungmin Park  * the partition definitions.
341*e29c22f5SKyungmin Park  * (Q: should we register the master MTD object as well?)
342*e29c22f5SKyungmin Park  */
343*e29c22f5SKyungmin Park 
344*e29c22f5SKyungmin Park int add_mtd_partitions(struct mtd_info *master,
345*e29c22f5SKyungmin Park 		       const struct mtd_partition *parts,
346*e29c22f5SKyungmin Park 		       int nbparts)
347*e29c22f5SKyungmin Park {
348*e29c22f5SKyungmin Park 	struct mtd_part *slave;
349*e29c22f5SKyungmin Park 	u_int32_t cur_offset = 0;
350*e29c22f5SKyungmin Park 	int i;
351*e29c22f5SKyungmin Park 
352*e29c22f5SKyungmin Park 	printk (KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name);
353*e29c22f5SKyungmin Park 
354*e29c22f5SKyungmin Park 	for (i = 0; i < nbparts; i++) {
355*e29c22f5SKyungmin Park 
356*e29c22f5SKyungmin Park 		/* allocate the partition structure */
357*e29c22f5SKyungmin Park 		slave = kzalloc (sizeof(*slave), GFP_KERNEL);
358*e29c22f5SKyungmin Park 		if (!slave) {
359*e29c22f5SKyungmin Park 			printk ("memory allocation error while creating partitions for \"%s\"\n",
360*e29c22f5SKyungmin Park 				master->name);
361*e29c22f5SKyungmin Park 			del_mtd_partitions(master);
362*e29c22f5SKyungmin Park 			return -ENOMEM;
363*e29c22f5SKyungmin Park 		}
364*e29c22f5SKyungmin Park 		list_add(&slave->list, &mtd_partitions);
365*e29c22f5SKyungmin Park 
366*e29c22f5SKyungmin Park 		/* set up the MTD object for this partition */
367*e29c22f5SKyungmin Park 		slave->mtd.type = master->type;
368*e29c22f5SKyungmin Park 		slave->mtd.flags = master->flags & ~parts[i].mask_flags;
369*e29c22f5SKyungmin Park 		slave->mtd.size = parts[i].size;
370*e29c22f5SKyungmin Park 		slave->mtd.writesize = master->writesize;
371*e29c22f5SKyungmin Park 		slave->mtd.oobsize = master->oobsize;
372*e29c22f5SKyungmin Park 		slave->mtd.oobavail = master->oobavail;
373*e29c22f5SKyungmin Park 		slave->mtd.subpage_sft = master->subpage_sft;
374*e29c22f5SKyungmin Park 
375*e29c22f5SKyungmin Park 		slave->mtd.name = parts[i].name;
376*e29c22f5SKyungmin Park 		slave->mtd.owner = master->owner;
377*e29c22f5SKyungmin Park 
378*e29c22f5SKyungmin Park 		slave->mtd.read = part_read;
379*e29c22f5SKyungmin Park 		slave->mtd.write = part_write;
380*e29c22f5SKyungmin Park 
381*e29c22f5SKyungmin Park #ifdef MTD_LINUX
382*e29c22f5SKyungmin Park 		if (master->panic_write)
383*e29c22f5SKyungmin Park 			slave->mtd.panic_write = part_panic_write;
384*e29c22f5SKyungmin Park 
385*e29c22f5SKyungmin Park 		if(master->point && master->unpoint){
386*e29c22f5SKyungmin Park 			slave->mtd.point = part_point;
387*e29c22f5SKyungmin Park 			slave->mtd.unpoint = part_unpoint;
388*e29c22f5SKyungmin Park 		}
389*e29c22f5SKyungmin Park #endif
390*e29c22f5SKyungmin Park 
391*e29c22f5SKyungmin Park 		if (master->read_oob)
392*e29c22f5SKyungmin Park 			slave->mtd.read_oob = part_read_oob;
393*e29c22f5SKyungmin Park 		if (master->write_oob)
394*e29c22f5SKyungmin Park 			slave->mtd.write_oob = part_write_oob;
395*e29c22f5SKyungmin Park 		if(master->read_user_prot_reg)
396*e29c22f5SKyungmin Park 			slave->mtd.read_user_prot_reg = part_read_user_prot_reg;
397*e29c22f5SKyungmin Park 		if(master->read_fact_prot_reg)
398*e29c22f5SKyungmin Park 			slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg;
399*e29c22f5SKyungmin Park 		if(master->write_user_prot_reg)
400*e29c22f5SKyungmin Park 			slave->mtd.write_user_prot_reg = part_write_user_prot_reg;
401*e29c22f5SKyungmin Park 		if(master->lock_user_prot_reg)
402*e29c22f5SKyungmin Park 			slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg;
403*e29c22f5SKyungmin Park 		if(master->get_user_prot_info)
404*e29c22f5SKyungmin Park 			slave->mtd.get_user_prot_info = part_get_user_prot_info;
405*e29c22f5SKyungmin Park 		if(master->get_fact_prot_info)
406*e29c22f5SKyungmin Park 			slave->mtd.get_fact_prot_info = part_get_fact_prot_info;
407*e29c22f5SKyungmin Park 		if (master->sync)
408*e29c22f5SKyungmin Park 			slave->mtd.sync = part_sync;
409*e29c22f5SKyungmin Park #ifdef MTD_LINUX
410*e29c22f5SKyungmin Park 		if (!i && master->suspend && master->resume) {
411*e29c22f5SKyungmin Park 				slave->mtd.suspend = part_suspend;
412*e29c22f5SKyungmin Park 				slave->mtd.resume = part_resume;
413*e29c22f5SKyungmin Park 		}
414*e29c22f5SKyungmin Park 		if (master->writev)
415*e29c22f5SKyungmin Park 			slave->mtd.writev = part_writev;
416*e29c22f5SKyungmin Park 		if (master->lock)
417*e29c22f5SKyungmin Park 			slave->mtd.lock = part_lock;
418*e29c22f5SKyungmin Park 		if (master->unlock)
419*e29c22f5SKyungmin Park 			slave->mtd.unlock = part_unlock;
420*e29c22f5SKyungmin Park #endif
421*e29c22f5SKyungmin Park 		if (master->block_isbad)
422*e29c22f5SKyungmin Park 			slave->mtd.block_isbad = part_block_isbad;
423*e29c22f5SKyungmin Park 		if (master->block_markbad)
424*e29c22f5SKyungmin Park 			slave->mtd.block_markbad = part_block_markbad;
425*e29c22f5SKyungmin Park 		slave->mtd.erase = part_erase;
426*e29c22f5SKyungmin Park 		slave->master = master;
427*e29c22f5SKyungmin Park 		slave->offset = parts[i].offset;
428*e29c22f5SKyungmin Park 		slave->index = i;
429*e29c22f5SKyungmin Park 
430*e29c22f5SKyungmin Park 		if (slave->offset == MTDPART_OFS_APPEND)
431*e29c22f5SKyungmin Park 			slave->offset = cur_offset;
432*e29c22f5SKyungmin Park 		if (slave->offset == MTDPART_OFS_NXTBLK) {
433*e29c22f5SKyungmin Park 			slave->offset = cur_offset;
434*e29c22f5SKyungmin Park 			if ((cur_offset % master->erasesize) != 0) {
435*e29c22f5SKyungmin Park 				/* Round up to next erasesize */
436*e29c22f5SKyungmin Park 				slave->offset = ((cur_offset / master->erasesize) + 1) * master->erasesize;
437*e29c22f5SKyungmin Park 				printk(KERN_NOTICE "Moving partition %d: "
438*e29c22f5SKyungmin Park 				       "0x%08x -> 0x%08x\n", i,
439*e29c22f5SKyungmin Park 				       cur_offset, slave->offset);
440*e29c22f5SKyungmin Park 			}
441*e29c22f5SKyungmin Park 		}
442*e29c22f5SKyungmin Park 		if (slave->mtd.size == MTDPART_SIZ_FULL)
443*e29c22f5SKyungmin Park 			slave->mtd.size = master->size - slave->offset;
444*e29c22f5SKyungmin Park 		cur_offset = slave->offset + slave->mtd.size;
445*e29c22f5SKyungmin Park 
446*e29c22f5SKyungmin Park 		printk (KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset,
447*e29c22f5SKyungmin Park 			slave->offset + slave->mtd.size, slave->mtd.name);
448*e29c22f5SKyungmin Park 
449*e29c22f5SKyungmin Park 		/* let's do some sanity checks */
450*e29c22f5SKyungmin Park 		if (slave->offset >= master->size) {
451*e29c22f5SKyungmin Park 				/* let's register it anyway to preserve ordering */
452*e29c22f5SKyungmin Park 			slave->offset = 0;
453*e29c22f5SKyungmin Park 			slave->mtd.size = 0;
454*e29c22f5SKyungmin Park 			printk ("mtd: partition \"%s\" is out of reach -- disabled\n",
455*e29c22f5SKyungmin Park 				parts[i].name);
456*e29c22f5SKyungmin Park 		}
457*e29c22f5SKyungmin Park 		if (slave->offset + slave->mtd.size > master->size) {
458*e29c22f5SKyungmin Park 			slave->mtd.size = master->size - slave->offset;
459*e29c22f5SKyungmin Park 			printk ("mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#x\n",
460*e29c22f5SKyungmin Park 				parts[i].name, master->name, slave->mtd.size);
461*e29c22f5SKyungmin Park 		}
462*e29c22f5SKyungmin Park 		if (master->numeraseregions>1) {
463*e29c22f5SKyungmin Park 			/* Deal with variable erase size stuff */
464*e29c22f5SKyungmin Park 			int i;
465*e29c22f5SKyungmin Park 			struct mtd_erase_region_info *regions = master->eraseregions;
466*e29c22f5SKyungmin Park 
467*e29c22f5SKyungmin Park 			/* Find the first erase regions which is part of this partition. */
468*e29c22f5SKyungmin Park 			for (i=0; i < master->numeraseregions && slave->offset >= regions[i].offset; i++)
469*e29c22f5SKyungmin Park 				;
470*e29c22f5SKyungmin Park 
471*e29c22f5SKyungmin Park 			for (i--; i < master->numeraseregions && slave->offset + slave->mtd.size > regions[i].offset; i++) {
472*e29c22f5SKyungmin Park 				if (slave->mtd.erasesize < regions[i].erasesize) {
473*e29c22f5SKyungmin Park 					slave->mtd.erasesize = regions[i].erasesize;
474*e29c22f5SKyungmin Park 				}
475*e29c22f5SKyungmin Park 			}
476*e29c22f5SKyungmin Park 		} else {
477*e29c22f5SKyungmin Park 			/* Single erase size */
478*e29c22f5SKyungmin Park 			slave->mtd.erasesize = master->erasesize;
479*e29c22f5SKyungmin Park 		}
480*e29c22f5SKyungmin Park 
481*e29c22f5SKyungmin Park 		if ((slave->mtd.flags & MTD_WRITEABLE) &&
482*e29c22f5SKyungmin Park 		    (slave->offset % slave->mtd.erasesize)) {
483*e29c22f5SKyungmin Park 			/* Doesn't start on a boundary of major erase size */
484*e29c22f5SKyungmin Park 			/* FIXME: Let it be writable if it is on a boundary of _minor_ erase size though */
485*e29c22f5SKyungmin Park 			slave->mtd.flags &= ~MTD_WRITEABLE;
486*e29c22f5SKyungmin Park 			printk ("mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
487*e29c22f5SKyungmin Park 				parts[i].name);
488*e29c22f5SKyungmin Park 		}
489*e29c22f5SKyungmin Park 		if ((slave->mtd.flags & MTD_WRITEABLE) &&
490*e29c22f5SKyungmin Park 		    (slave->mtd.size % slave->mtd.erasesize)) {
491*e29c22f5SKyungmin Park 			slave->mtd.flags &= ~MTD_WRITEABLE;
492*e29c22f5SKyungmin Park 			printk ("mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
493*e29c22f5SKyungmin Park 				parts[i].name);
494*e29c22f5SKyungmin Park 		}
495*e29c22f5SKyungmin Park 
496*e29c22f5SKyungmin Park 		slave->mtd.ecclayout = master->ecclayout;
497*e29c22f5SKyungmin Park 		if (master->block_isbad) {
498*e29c22f5SKyungmin Park 			uint32_t offs = 0;
499*e29c22f5SKyungmin Park 
500*e29c22f5SKyungmin Park 			while(offs < slave->mtd.size) {
501*e29c22f5SKyungmin Park 				if (master->block_isbad(master,
502*e29c22f5SKyungmin Park 							offs + slave->offset))
503*e29c22f5SKyungmin Park 					slave->mtd.ecc_stats.badblocks++;
504*e29c22f5SKyungmin Park 				offs += slave->mtd.erasesize;
505*e29c22f5SKyungmin Park 			}
506*e29c22f5SKyungmin Park 		}
507*e29c22f5SKyungmin Park 
508*e29c22f5SKyungmin Park #ifdef MTD_LINUX
509*e29c22f5SKyungmin Park 		if (parts[i].mtdp) {
510*e29c22f5SKyungmin Park 			/* store the object pointer
511*e29c22f5SKyungmin Park 			 * (caller may or may not register it */
512*e29c22f5SKyungmin Park 			*parts[i].mtdp = &slave->mtd;
513*e29c22f5SKyungmin Park 			slave->registered = 0;
514*e29c22f5SKyungmin Park 		} else {
515*e29c22f5SKyungmin Park 			/* register our partition */
516*e29c22f5SKyungmin Park 			add_mtd_device(&slave->mtd);
517*e29c22f5SKyungmin Park 			slave->registered = 1;
518*e29c22f5SKyungmin Park 		}
519*e29c22f5SKyungmin Park #else
520*e29c22f5SKyungmin Park 		/* register our partition */
521*e29c22f5SKyungmin Park 		add_mtd_device(&slave->mtd);
522*e29c22f5SKyungmin Park 		slave->registered = 1;
523*e29c22f5SKyungmin Park #endif
524*e29c22f5SKyungmin Park 	}
525*e29c22f5SKyungmin Park 
526*e29c22f5SKyungmin Park 	return 0;
527*e29c22f5SKyungmin Park }
528*e29c22f5SKyungmin Park 
529*e29c22f5SKyungmin Park #ifdef MTD_LINUX
530*e29c22f5SKyungmin Park EXPORT_SYMBOL(add_mtd_partitions);
531*e29c22f5SKyungmin Park EXPORT_SYMBOL(del_mtd_partitions);
532*e29c22f5SKyungmin Park #endif
533