All of lore.kernel.org
 help / color / mirror / Atom feed
From: Miquel Raynal <miquel.raynal@bootlin.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH v7 08/12] mtd: mtdpart: implement proper partition handling
Date: Thu,  6 Sep 2018 09:08:50 +0200	[thread overview]
Message-ID: <20180906070854.9717-9-miquel.raynal@bootlin.com> (raw)
In-Reply-To: <20180906070854.9717-1-miquel.raynal@bootlin.com>

Instead of collecting partitions in a flat list, create a hierarchy
within the mtd_info structure: use a partitions list to keep track of
the partitions of an MTD device (which might be itself a partition of
another MTD device), a pointer to the parent device (NULL when the MTD
device is the root one, not a partition).

By also saving directly in mtd_info the offset of the partition, we
can get rid of the mtd_part structure.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Reviewed-by: Stefan Roese <sr@denx.de>
---
 drivers/mtd/mtdcore.c          |   2 +
 drivers/mtd/mtdpart.c          | 412 ++++++++++++++-------------------
 include/linux/mtd/mtd.h        |  31 +++
 include/linux/mtd/partitions.h |   1 -
 4 files changed, 208 insertions(+), 238 deletions(-)

diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index fb1d68d5e2..fb6c779abb 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -426,6 +426,8 @@ int add_mtd_device(struct mtd_info *mtd)
 	mtd->index = i;
 	mtd->usecount = 0;
 
+	INIT_LIST_HEAD(&mtd->partitions);
+
 	/* default value if not set by driver */
 	if (mtd->bitflip_threshold == 0)
 		mtd->bitflip_threshold = mtd->ecc_strength;
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 09427b7b87..fae780855d 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -29,29 +29,12 @@
 
 #include "mtdcore.h"
 
-/* Our partition linked list */
-static LIST_HEAD(mtd_partitions);
 #ifndef __UBOOT__
 static DEFINE_MUTEX(mtd_partitions_mutex);
 #else
 DEFINE_MUTEX(mtd_partitions_mutex);
 #endif
 
-/* Our partition node structure */
-struct mtd_part {
-	struct mtd_info mtd;
-	struct mtd_info *master;
-	uint64_t offset;
-	struct list_head list;
-};
-
-/*
- * Given a pointer to the MTD object in the mtd_part structure, we can retrieve
- * the pointer to that structure with this macro.
- */
-#define PART(x)  ((struct mtd_part *)(x))
-
-
 #ifdef __UBOOT__
 /* from mm/util.c */
 
@@ -332,19 +315,18 @@ int mtd_search_alternate_name(const char *mtdname, char *altname,
 static int part_read(struct mtd_info *mtd, loff_t from, size_t len,
 		size_t *retlen, u_char *buf)
 {
-	struct mtd_part *part = PART(mtd);
 	struct mtd_ecc_stats stats;
 	int res;
 
-	stats = part->master->ecc_stats;
-	res = part->master->_read(part->master, from + part->offset, len,
-				  retlen, buf);
+	stats = mtd->parent->ecc_stats;
+	res = mtd->parent->_read(mtd->parent, from + mtd->offset, len,
+				 retlen, buf);
 	if (unlikely(mtd_is_eccerr(res)))
 		mtd->ecc_stats.failed +=
-			part->master->ecc_stats.failed - stats.failed;
+			mtd->parent->ecc_stats.failed - stats.failed;
 	else
 		mtd->ecc_stats.corrected +=
-			part->master->ecc_stats.corrected - stats.corrected;
+			mtd->parent->ecc_stats.corrected - stats.corrected;
 	return res;
 }
 
@@ -352,17 +334,13 @@ static int part_read(struct mtd_info *mtd, loff_t from, size_t len,
 static int part_point(struct mtd_info *mtd, loff_t from, size_t len,
 		size_t *retlen, void **virt, resource_size_t *phys)
 {
-	struct mtd_part *part = PART(mtd);
-
-	return part->master->_point(part->master, from + part->offset, len,
-				    retlen, virt, phys);
+	return mtd->parent->_point(mtd->parent, from + mtd->offset, len,
+				   retlen, virt, phys);
 }
 
 static int part_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
 {
-	struct mtd_part *part = PART(mtd);
-
-	return part->master->_unpoint(part->master, from + part->offset, len);
+	return mtd->parent->_unpoint(mtd->parent, from + mtd->offset, len);
 }
 #endif
 
@@ -371,17 +349,13 @@ static unsigned long part_get_unmapped_area(struct mtd_info *mtd,
 					    unsigned long offset,
 					    unsigned long flags)
 {
-	struct mtd_part *part = PART(mtd);
-
-	offset += part->offset;
-	return part->master->_get_unmapped_area(part->master, len, offset,
-						flags);
+	offset += mtd->offset;
+	return mtd->parent->_get_unmapped_area(mtd->parent, len, offset, flags);
 }
 
 static int part_read_oob(struct mtd_info *mtd, loff_t from,
 		struct mtd_oob_ops *ops)
 {
-	struct mtd_part *part = PART(mtd);
 	int res;
 
 	if (from >= mtd->size)
@@ -406,7 +380,7 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from,
 			return -EINVAL;
 	}
 
-	res = part->master->_read_oob(part->master, from + part->offset, ops);
+	res = mtd->parent->_read_oob(mtd->parent, from + mtd->offset, ops);
 	if (unlikely(res)) {
 		if (mtd_is_bitflip(res))
 			mtd->ecc_stats.corrected++;
@@ -419,99 +393,87 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from,
 static int part_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
 		size_t len, size_t *retlen, u_char *buf)
 {
-	struct mtd_part *part = PART(mtd);
-	return part->master->_read_user_prot_reg(part->master, from, len,
-						 retlen, buf);
+	return mtd->parent->_read_user_prot_reg(mtd->parent, from, len,
+						retlen, buf);
 }
 
 static int part_get_user_prot_info(struct mtd_info *mtd, size_t len,
 				   size_t *retlen, struct otp_info *buf)
 {
-	struct mtd_part *part = PART(mtd);
-	return part->master->_get_user_prot_info(part->master, len, retlen,
-						 buf);
+	return mtd->parent->_get_user_prot_info(mtd->parent, len, retlen,
+						buf);
 }
 
 static int part_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
 		size_t len, size_t *retlen, u_char *buf)
 {
-	struct mtd_part *part = PART(mtd);
-	return part->master->_read_fact_prot_reg(part->master, from, len,
-						 retlen, buf);
+	return mtd->parent->_read_fact_prot_reg(mtd->parent, from, len,
+						retlen, buf);
 }
 
 static int part_get_fact_prot_info(struct mtd_info *mtd, size_t len,
 				   size_t *retlen, struct otp_info *buf)
 {
-	struct mtd_part *part = PART(mtd);
-	return part->master->_get_fact_prot_info(part->master, len, retlen,
-						 buf);
+	return mtd->parent->_get_fact_prot_info(mtd->parent, len, retlen,
+						buf);
 }
 
 static int part_write(struct mtd_info *mtd, loff_t to, size_t len,
 		size_t *retlen, const u_char *buf)
 {
-	struct mtd_part *part = PART(mtd);
-	return part->master->_write(part->master, to + part->offset, len,
-				    retlen, buf);
+	return mtd->parent->_write(mtd->parent, to + mtd->offset, len,
+				   retlen, buf);
 }
 
 static int part_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
 		size_t *retlen, const u_char *buf)
 {
-	struct mtd_part *part = PART(mtd);
-	return part->master->_panic_write(part->master, to + part->offset, len,
-					  retlen, buf);
+	return mtd->parent->_panic_write(mtd->parent, to + mtd->offset, len,
+					 retlen, buf);
 }
 
 static int part_write_oob(struct mtd_info *mtd, loff_t to,
 		struct mtd_oob_ops *ops)
 {
-	struct mtd_part *part = PART(mtd);
-
 	if (to >= mtd->size)
 		return -EINVAL;
 	if (ops->datbuf && to + ops->len > mtd->size)
 		return -EINVAL;
-	return part->master->_write_oob(part->master, to + part->offset, ops);
+	return mtd->parent->_write_oob(mtd->parent, to + mtd->offset, ops);
 }
 
 static int part_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
 		size_t len, size_t *retlen, u_char *buf)
 {
-	struct mtd_part *part = PART(mtd);
-	return part->master->_write_user_prot_reg(part->master, from, len,
-						  retlen, buf);
+	return mtd->parent->_write_user_prot_reg(mtd->parent, from, len,
+						 retlen, buf);
 }
 
 static int part_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
 		size_t len)
 {
-	struct mtd_part *part = PART(mtd);
-	return part->master->_lock_user_prot_reg(part->master, from, len);
+	return mtd->parent->_lock_user_prot_reg(mtd->parent, from, len);
 }
 
 #ifndef __UBOOT__
 static int part_writev(struct mtd_info *mtd, const struct kvec *vecs,
 		unsigned long count, loff_t to, size_t *retlen)
 {
-	struct mtd_part *part = PART(mtd);
-	return part->master->_writev(part->master, vecs, count,
-				     to + part->offset, retlen);
+	return mtd->parent->_writev(mtd->parent, vecs, count,
+				    to + mtd->offset, retlen);
 }
 #endif
 
 static int part_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
-	struct mtd_part *part = PART(mtd);
 	int ret;
 
-	instr->addr += part->offset;
-	ret = part->master->_erase(part->master, instr);
+	instr->addr += mtd->offset;
+	ret = mtd->parent->_erase(mtd->parent, instr);
 	if (ret) {
 		if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
-			instr->fail_addr -= part->offset;
-		instr->addr -= part->offset;
+			instr->fail_addr -= mtd->offset;
+		instr->addr -= mtd->offset;
 	}
 	return ret;
 }
@@ -519,11 +481,9 @@ static int part_erase(struct mtd_info *mtd, struct erase_info *instr)
 void mtd_erase_callback(struct erase_info *instr)
 {
 	if (instr->mtd->_erase == part_erase) {
-		struct mtd_part *part = PART(instr->mtd);
-
 		if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
-			instr->fail_addr -= part->offset;
-		instr->addr -= part->offset;
+			instr->fail_addr -= instr->mtd->offset;
+		instr->addr -= instr->mtd->offset;
 	}
 	if (instr->callback)
 		instr->callback(instr);
@@ -532,107 +492,112 @@ EXPORT_SYMBOL_GPL(mtd_erase_callback);
 
 static int part_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
 {
-	struct mtd_part *part = PART(mtd);
-	return part->master->_lock(part->master, ofs + part->offset, len);
+	return mtd->parent->_lock(mtd->parent, ofs + mtd->offset, len);
 }
 
 static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
 {
-	struct mtd_part *part = PART(mtd);
-	return part->master->_unlock(part->master, ofs + part->offset, len);
+	return mtd->parent->_unlock(mtd->parent, ofs + mtd->offset, len);
 }
 
 static int part_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
 {
-	struct mtd_part *part = PART(mtd);
-	return part->master->_is_locked(part->master, ofs + part->offset, len);
+	return mtd->parent->_is_locked(mtd->parent, ofs + mtd->offset, len);
 }
 
 static void part_sync(struct mtd_info *mtd)
 {
-	struct mtd_part *part = PART(mtd);
-	part->master->_sync(part->master);
+	mtd->parent->_sync(mtd->parent);
 }
 
 #ifndef __UBOOT__
 static int part_suspend(struct mtd_info *mtd)
 {
-	struct mtd_part *part = PART(mtd);
-	return part->master->_suspend(part->master);
+	return mtd->parent->_suspend(mtd->parent);
 }
 
 static void part_resume(struct mtd_info *mtd)
 {
-	struct mtd_part *part = PART(mtd);
-	part->master->_resume(part->master);
+	mtd->parent->_resume(mtd->parent);
 }
 #endif
 
 static int part_block_isreserved(struct mtd_info *mtd, loff_t ofs)
 {
-	struct mtd_part *part = PART(mtd);
-	ofs += part->offset;
-	return part->master->_block_isreserved(part->master, ofs);
+	ofs += mtd->offset;
+	return mtd->parent->_block_isreserved(mtd->parent, ofs);
 }
 
 static int part_block_isbad(struct mtd_info *mtd, loff_t ofs)
 {
-	struct mtd_part *part = PART(mtd);
-	ofs += part->offset;
-	return part->master->_block_isbad(part->master, ofs);
+	ofs += mtd->offset;
+	return mtd->parent->_block_isbad(mtd->parent, ofs);
 }
 
 static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
 {
-	struct mtd_part *part = PART(mtd);
 	int res;
 
-	ofs += part->offset;
-	res = part->master->_block_markbad(part->master, ofs);
+	ofs += mtd->offset;
+	res = mtd->parent->_block_markbad(mtd->parent, ofs);
 	if (!res)
 		mtd->ecc_stats.badblocks++;
 	return res;
 }
 
-static inline void free_partition(struct mtd_part *p)
+static inline void free_partition(struct mtd_info *p)
 {
-	kfree(p->mtd.name);
+	kfree(p->name);
 	kfree(p);
 }
 
 /*
  * This function unregisters and destroy all slave MTD objects which are
- * attached to the given master MTD object.
+ * attached to the given master MTD object, recursively.
  */
-
-int del_mtd_partitions(struct mtd_info *master)
+static int do_del_mtd_partitions(struct mtd_info *master)
 {
-	struct mtd_part *slave, *next;
+	struct mtd_info *slave, *next;
 	int ret, err = 0;
 
-	debug("Deleting MTD partitions on \"%s\":\n", master->name);
+	list_for_each_entry_safe(slave, next, &master->partitions, node) {
+		if (mtd_has_partitions(slave))
+			del_mtd_partitions(slave);
 
-	mutex_lock(&mtd_partitions_mutex);
-	list_for_each_entry_safe(slave, next, &mtd_partitions, list)
-		if (slave->master == master) {
-			ret = del_mtd_device(&slave->mtd);
-			if (ret < 0) {
-				err = ret;
-				continue;
-			}
-			list_del(&slave->list);
-			free_partition(slave);
+		debug("Deleting %s MTD partition\n", slave->name);
+		ret = del_mtd_device(slave);
+		if (ret < 0) {
+			printf("Error when deleting partition \"%s\" (%d)\n",
+			       slave->name, ret);
+			err = ret;
+			continue;
 		}
-	mutex_unlock(&mtd_partitions_mutex);
+
+		list_del(&slave->node);
+		free_partition(slave);
+	}
 
 	return err;
 }
 
-static struct mtd_part *allocate_partition(struct mtd_info *master,
-			const struct mtd_partition *part, int partno,
-			uint64_t cur_offset)
+int del_mtd_partitions(struct mtd_info *master)
 {
-	struct mtd_part *slave;
+	int ret;
+
+	debug("Deleting MTD partitions on \"%s\":\n", master->name);
+
+	mutex_lock(&mtd_partitions_mutex);
+	ret = do_del_mtd_partitions(master);
+	mutex_unlock(&mtd_partitions_mutex);
+
+	return ret;
+}
+
+static struct mtd_info *allocate_partition(struct mtd_info *master,
+					   const struct mtd_partition *part,
+					   int partno, uint64_t cur_offset)
+{
+	struct mtd_info *slave;
 	char *name;
 
 	/* allocate the partition structure */
@@ -647,85 +612,87 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
 	}
 
 	/* set up the MTD object for this partition */
-	slave->mtd.type = master->type;
-	slave->mtd.flags = master->flags & ~part->mask_flags;
-	slave->mtd.size = part->size;
-	slave->mtd.writesize = master->writesize;
-	slave->mtd.writebufsize = master->writebufsize;
-	slave->mtd.oobsize = master->oobsize;
-	slave->mtd.oobavail = master->oobavail;
-	slave->mtd.subpage_sft = master->subpage_sft;
+	slave->type = master->type;
+	slave->flags = master->flags & ~part->mask_flags;
+	slave->size = part->size;
+	slave->writesize = master->writesize;
+	slave->writebufsize = master->writebufsize;
+	slave->oobsize = master->oobsize;
+	slave->oobavail = master->oobavail;
+	slave->subpage_sft = master->subpage_sft;
 
-	slave->mtd.name = name;
-	slave->mtd.owner = master->owner;
+	slave->name = name;
+	slave->owner = master->owner;
 #ifndef __UBOOT__
-	slave->mtd.backing_dev_info = master->backing_dev_info;
+	slave->backing_dev_info = master->backing_dev_info;
 
 	/* NOTE:  we don't arrange MTDs as a tree; it'd be error-prone
 	 * to have the same data be in two different partitions.
 	 */
-	slave->mtd.dev.parent = master->dev.parent;
+	slave->dev.parent = master->dev.parent;
 #endif
 
 	if (master->_read)
-		slave->mtd._read = part_read;
+		slave->_read = part_read;
 	if (master->_write)
-		slave->mtd._write = part_write;
+		slave->_write = part_write;
 
 	if (master->_panic_write)
-		slave->mtd._panic_write = part_panic_write;
+		slave->_panic_write = part_panic_write;
 
 #ifndef __UBOOT__
 	if (master->_point && master->_unpoint) {
-		slave->mtd._point = part_point;
-		slave->mtd._unpoint = part_unpoint;
+		slave->_point = part_point;
+		slave->_unpoint = part_unpoint;
 	}
 #endif
 
 	if (master->_get_unmapped_area)
-		slave->mtd._get_unmapped_area = part_get_unmapped_area;
+		slave->_get_unmapped_area = part_get_unmapped_area;
 	if (master->_read_oob)
-		slave->mtd._read_oob = part_read_oob;
+		slave->_read_oob = part_read_oob;
 	if (master->_write_oob)
-		slave->mtd._write_oob = part_write_oob;
+		slave->_write_oob = part_write_oob;
 	if (master->_read_user_prot_reg)
-		slave->mtd._read_user_prot_reg = part_read_user_prot_reg;
+		slave->_read_user_prot_reg = part_read_user_prot_reg;
 	if (master->_read_fact_prot_reg)
-		slave->mtd._read_fact_prot_reg = part_read_fact_prot_reg;
+		slave->_read_fact_prot_reg = part_read_fact_prot_reg;
 	if (master->_write_user_prot_reg)
-		slave->mtd._write_user_prot_reg = part_write_user_prot_reg;
+		slave->_write_user_prot_reg = part_write_user_prot_reg;
 	if (master->_lock_user_prot_reg)
-		slave->mtd._lock_user_prot_reg = part_lock_user_prot_reg;
+		slave->_lock_user_prot_reg = part_lock_user_prot_reg;
 	if (master->_get_user_prot_info)
-		slave->mtd._get_user_prot_info = part_get_user_prot_info;
+		slave->_get_user_prot_info = part_get_user_prot_info;
 	if (master->_get_fact_prot_info)
-		slave->mtd._get_fact_prot_info = part_get_fact_prot_info;
+		slave->_get_fact_prot_info = part_get_fact_prot_info;
 	if (master->_sync)
-		slave->mtd._sync = part_sync;
+		slave->_sync = part_sync;
 #ifndef __UBOOT__
 	if (!partno && !master->dev.class && master->_suspend &&
 	    master->_resume) {
-			slave->mtd._suspend = part_suspend;
-			slave->mtd._resume = part_resume;
+		slave->_suspend = part_suspend;
+		slave->_resume = part_resume;
 	}
 	if (master->_writev)
-		slave->mtd._writev = part_writev;
+		slave->_writev = part_writev;
 #endif
 	if (master->_lock)
-		slave->mtd._lock = part_lock;
+		slave->_lock = part_lock;
 	if (master->_unlock)
-		slave->mtd._unlock = part_unlock;
+		slave->_unlock = part_unlock;
 	if (master->_is_locked)
-		slave->mtd._is_locked = part_is_locked;
+		slave->_is_locked = part_is_locked;
 	if (master->_block_isreserved)
-		slave->mtd._block_isreserved = part_block_isreserved;
+		slave->_block_isreserved = part_block_isreserved;
 	if (master->_block_isbad)
-		slave->mtd._block_isbad = part_block_isbad;
+		slave->_block_isbad = part_block_isbad;
 	if (master->_block_markbad)
-		slave->mtd._block_markbad = part_block_markbad;
-	slave->mtd._erase = part_erase;
-	slave->master = master;
+		slave->_block_markbad = part_block_markbad;
+	slave->_erase = part_erase;
+	slave->parent = master;
 	slave->offset = part->offset;
+	INIT_LIST_HEAD(&slave->partitions);
+	INIT_LIST_HEAD(&slave->node);
 
 	if (slave->offset == MTDPART_OFS_APPEND)
 		slave->offset = cur_offset;
@@ -741,41 +708,41 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
 	}
 	if (slave->offset == MTDPART_OFS_RETAIN) {
 		slave->offset = cur_offset;
-		if (master->size - slave->offset >= slave->mtd.size) {
-			slave->mtd.size = master->size - slave->offset
-							- slave->mtd.size;
+		if (master->size - slave->offset >= slave->size) {
+			slave->size = master->size - slave->offset
+							- slave->size;
 		} else {
 			debug("mtd partition \"%s\" doesn't have enough space: %#llx < %#llx, disabled\n",
 				part->name, master->size - slave->offset,
-				slave->mtd.size);
+				slave->size);
 			/* register to preserve ordering */
 			goto out_register;
 		}
 	}
-	if (slave->mtd.size == MTDPART_SIZ_FULL)
-		slave->mtd.size = master->size - slave->offset;
+	if (slave->size == MTDPART_SIZ_FULL)
+		slave->size = master->size - slave->offset;
 
 	debug("0x%012llx-0x%012llx : \"%s\"\n", (unsigned long long)slave->offset,
-		(unsigned long long)(slave->offset + slave->mtd.size), slave->mtd.name);
+		(unsigned long long)(slave->offset + slave->size), slave->name);
 
 	/* let's do some sanity checks */
 	if (slave->offset >= master->size) {
 		/* let's register it anyway to preserve ordering */
 		slave->offset = 0;
-		slave->mtd.size = 0;
+		slave->size = 0;
 		printk(KERN_ERR"mtd: partition \"%s\" is out of reach -- disabled\n",
 			part->name);
 		goto out_register;
 	}
-	if (slave->offset + slave->mtd.size > master->size) {
-		slave->mtd.size = master->size - slave->offset;
+	if (slave->offset + slave->size > master->size) {
+		slave->size = master->size - slave->offset;
 		printk(KERN_WARNING"mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#llx\n",
-			part->name, master->name, (unsigned long long)slave->mtd.size);
+		       part->name, master->name, slave->size);
 	}
 	if (master->numeraseregions > 1) {
 		/* Deal with variable erase size stuff */
 		int i, max = master->numeraseregions;
-		u64 end = slave->offset + slave->mtd.size;
+		u64 end = slave->offset + slave->size;
 		struct mtd_erase_region_info *regions = master->eraseregions;
 
 		/* Find the first erase regions which is part of this
@@ -788,44 +755,44 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
 
 		/* Pick biggest erasesize */
 		for (; i < max && regions[i].offset < end; i++) {
-			if (slave->mtd.erasesize < regions[i].erasesize) {
-				slave->mtd.erasesize = regions[i].erasesize;
+			if (slave->erasesize < regions[i].erasesize) {
+				slave->erasesize = regions[i].erasesize;
 			}
 		}
-		BUG_ON(slave->mtd.erasesize == 0);
+		BUG_ON(slave->erasesize == 0);
 	} else {
 		/* Single erase size */
-		slave->mtd.erasesize = master->erasesize;
+		slave->erasesize = master->erasesize;
 	}
 
-	if ((slave->mtd.flags & MTD_WRITEABLE) &&
-	    mtd_mod_by_eb(slave->offset, &slave->mtd)) {
+	if ((slave->flags & MTD_WRITEABLE) &&
+	    mtd_mod_by_eb(slave->offset, slave)) {
 		/* Doesn't start on a boundary of major erase size */
 		/* FIXME: Let it be writable if it is on a boundary of
 		 * _minor_ erase size though */
-		slave->mtd.flags &= ~MTD_WRITEABLE;
+		slave->flags &= ~MTD_WRITEABLE;
 		printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
 			part->name);
 	}
-	if ((slave->mtd.flags & MTD_WRITEABLE) &&
-	    mtd_mod_by_eb(slave->mtd.size, &slave->mtd)) {
-		slave->mtd.flags &= ~MTD_WRITEABLE;
+	if ((slave->flags & MTD_WRITEABLE) &&
+	    mtd_mod_by_eb(slave->size, slave)) {
+		slave->flags &= ~MTD_WRITEABLE;
 		printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
 			part->name);
 	}
 
-	slave->mtd.ecclayout = master->ecclayout;
-	slave->mtd.ecc_step_size = master->ecc_step_size;
-	slave->mtd.ecc_strength = master->ecc_strength;
-	slave->mtd.bitflip_threshold = master->bitflip_threshold;
+	slave->ecclayout = master->ecclayout;
+	slave->ecc_step_size = master->ecc_step_size;
+	slave->ecc_strength = master->ecc_strength;
+	slave->bitflip_threshold = master->bitflip_threshold;
 
 	if (master->_block_isbad) {
 		uint64_t offs = 0;
 
-		while (offs < slave->mtd.size) {
+		while (offs < slave->size) {
 			if (mtd_block_isbad(master, offs + slave->offset))
-				slave->mtd.ecc_stats.badblocks++;
-			offs += slave->mtd.erasesize;
+				slave->ecc_stats.badblocks++;
+			offs += slave->erasesize;
 		}
 	}
 
@@ -838,7 +805,7 @@ int mtd_add_partition(struct mtd_info *master, const char *name,
 		      long long offset, long long length)
 {
 	struct mtd_partition part;
-	struct mtd_part *p, *new;
+	struct mtd_info *p, *new;
 	uint64_t start, end;
 	int ret = 0;
 
@@ -867,21 +834,20 @@ int mtd_add_partition(struct mtd_info *master, const char *name,
 	end = offset + length;
 
 	mutex_lock(&mtd_partitions_mutex);
-	list_for_each_entry(p, &mtd_partitions, list)
-		if (p->master == master) {
-			if ((start >= p->offset) &&
-			    (start < (p->offset + p->mtd.size)))
-				goto err_inv;
+	list_for_each_entry(p, &master->partitions, node) {
+		if (start >= p->offset &&
+		    (start < (p->offset + p->size)))
+			goto err_inv;
 
-			if ((end >= p->offset) &&
-			    (end < (p->offset + p->mtd.size)))
-				goto err_inv;
-		}
+		if (end >= p->offset &&
+		    (end < (p->offset + p->size)))
+			goto err_inv;
+	}
 
-	list_add(&new->list, &mtd_partitions);
+	list_add_tail(&new->node, &master->partitions);
 	mutex_unlock(&mtd_partitions_mutex);
 
-	add_mtd_device(&new->mtd);
+	add_mtd_device(new);
 
 	return ret;
 err_inv:
@@ -893,18 +859,17 @@ EXPORT_SYMBOL_GPL(mtd_add_partition);
 
 int mtd_del_partition(struct mtd_info *master, int partno)
 {
-	struct mtd_part *slave, *next;
+	struct mtd_info *slave, *next;
 	int ret = -EINVAL;
 
 	mutex_lock(&mtd_partitions_mutex);
-	list_for_each_entry_safe(slave, next, &mtd_partitions, list)
-		if ((slave->master == master) &&
-		    (slave->mtd.index == partno)) {
-			ret = del_mtd_device(&slave->mtd);
+	list_for_each_entry_safe(slave, next, &master->partitions, node)
+		if (slave->index == partno) {
+			ret = del_mtd_device(slave);
 			if (ret < 0)
 				break;
 
-			list_del(&slave->list);
+			list_del(&slave->node);
 			free_partition(slave);
 			break;
 		}
@@ -928,20 +893,10 @@ int add_mtd_partitions(struct mtd_info *master,
 		       const struct mtd_partition *parts,
 		       int nbparts)
 {
-	struct mtd_part *slave;
+	struct mtd_info *slave;
 	uint64_t cur_offset = 0;
 	int i;
 
-#ifdef __UBOOT__
-	/*
-	 * Need to init the list here, since LIST_INIT() does not
-	 * work on platforms where relocation has problems (like MIPS
-	 * & PPC).
-	 */
-	if (mtd_partitions.next == NULL)
-		INIT_LIST_HEAD(&mtd_partitions);
-#endif
-
 	debug("Creating %d MTD partitions on \"%s\":\n", nbparts, master->name);
 
 	for (i = 0; i < nbparts; i++) {
@@ -950,12 +905,12 @@ int add_mtd_partitions(struct mtd_info *master,
 			return PTR_ERR(slave);
 
 		mutex_lock(&mtd_partitions_mutex);
-		list_add(&slave->list, &mtd_partitions);
+		list_add_tail(&slave->node, &master->partitions);
 		mutex_unlock(&mtd_partitions_mutex);
 
-		add_mtd_device(&slave->mtd);
+		add_mtd_device(slave);
 
-		cur_offset = slave->offset + slave->mtd.size;
+		cur_offset = slave->offset + slave->size;
 	}
 
 	return 0;
@@ -1058,29 +1013,12 @@ int parse_mtd_partitions(struct mtd_info *master, const char *const *types,
 }
 #endif
 
-int mtd_is_partition(const struct mtd_info *mtd)
-{
-	struct mtd_part *part;
-	int ispart = 0;
-
-	mutex_lock(&mtd_partitions_mutex);
-	list_for_each_entry(part, &mtd_partitions, list)
-		if (&part->mtd == mtd) {
-			ispart = 1;
-			break;
-		}
-	mutex_unlock(&mtd_partitions_mutex);
-
-	return ispart;
-}
-EXPORT_SYMBOL_GPL(mtd_is_partition);
-
 /* Returns the size of the entire flash chip */
 uint64_t mtd_get_device_size(const struct mtd_info *mtd)
 {
-	if (!mtd_is_partition(mtd))
-		return mtd->size;
+	if (mtd_is_partition(mtd))
+		return mtd->parent->size;
 
-	return PART(mtd)->master->size;
+	return mtd->size;
 }
 EXPORT_SYMBOL_GPL(mtd_get_device_size);
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index b8c2c3fd59..ba582d38bc 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -307,6 +307,27 @@ struct mtd_info {
 	struct udevice *dev;
 #endif
 	int usecount;
+
+	/* MTD devices do not have any parent. MTD partitions do. */
+	struct mtd_info *parent;
+
+	/*
+	 * Offset of the partition relatively to the parent offset.
+	 * Is 0 for real MTD devices (ie. not partitions).
+	 */
+	u64 offset;
+
+	/*
+	 * List node used to add an MTD partition to the parent
+	 * partition list.
+	 */
+	struct list_head node;
+
+	/*
+	 * List of partitions attached to this MTD device (the parent
+	 * MTD device can itself be a partition).
+	 */
+	struct list_head partitions;
 };
 
 #if IS_ENABLED(CONFIG_DM)
@@ -334,6 +355,16 @@ static inline const struct device_node *mtd_get_of_node(struct mtd_info *mtd)
 }
 #endif
 
+static inline bool mtd_is_partition(const struct mtd_info *mtd)
+{
+	return mtd->parent;
+}
+
+static inline bool mtd_has_partitions(const struct mtd_info *mtd)
+{
+	return !list_empty(&mtd->partitions);
+}
+
 int mtd_ooblayout_ecc(struct mtd_info *mtd, int section,
 		      struct mtd_oob_region *oobecc);
 int mtd_ooblayout_find_eccregion(struct mtd_info *mtd, int eccbyte,
diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h
index 082a4966ea..b8db1b0a58 100644
--- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h
@@ -81,7 +81,6 @@ extern void register_mtd_parser(struct mtd_part_parser *parser);
 extern void deregister_mtd_parser(struct mtd_part_parser *parser);
 #endif
 
-int mtd_is_partition(const struct mtd_info *mtd);
 int mtd_add_partition(struct mtd_info *master, const char *name,
 		      long long offset, long long length);
 int mtd_del_partition(struct mtd_info *master, int partno);
-- 
2.17.1

  parent reply	other threads:[~2018-09-06  7:08 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-09-06  7:08 [U-Boot] [PATCH v7 00/12] SPI-NAND support Miquel Raynal
2018-09-06  7:08 ` [U-Boot] [PATCH v7 01/12] lib: strto: parse all lowercase metric prefixes in ustrtoul[l] Miquel Raynal
2018-09-06  7:08 ` [U-Boot] [PATCH v7 02/12] lib: strto: fix metric suffix parsing in strtoul[l] Miquel Raynal
2018-09-06  7:08 ` [U-Boot] [PATCH v7 03/12] cmd: mtdparts: accept spi-nand devices Miquel Raynal
2018-09-06  7:08 ` [U-Boot] [PATCH v7 04/12] cmd: mtdparts: remove mandatory 'mtdparts=' prefix Miquel Raynal
2018-09-06  7:08 ` [U-Boot] [PATCH v7 05/12] mtd: uclass: add probe function Miquel Raynal
2018-09-06  7:08 ` [U-Boot] [PATCH v7 06/12] mtd: uclass: add a generic 'mtdparts' parser Miquel Raynal
2018-09-06  7:08 ` [U-Boot] [PATCH v7 07/12] mtd: uclass: search for an equivalent MTD name with the mtdids Miquel Raynal
2018-09-06  7:08 ` Miquel Raynal [this message]
2018-09-06  7:08 ` [U-Boot] [PATCH v7 09/12] cmd: mtd: add 'mtd' command Miquel Raynal
2018-09-06  9:42   ` Boris Brezillon
2018-09-06  7:08 ` [U-Boot] [PATCH v7 10/12] cmd: mtdparts: try to probe the MTD devices as a fallback Miquel Raynal
2018-09-06  9:46   ` Boris Brezillon
2018-09-06  7:08 ` [U-Boot] [PATCH v7 11/12] cmd: ubi: clean the partition handling Miquel Raynal
2018-09-06  9:52   ` Boris Brezillon
2018-09-06  7:08 ` [U-Boot] [PATCH v7 12/12] cmd: mtdparts: describe as legacy Miquel Raynal
2018-09-06  9:57   ` Boris Brezillon
2018-09-06  7:15 ` [U-Boot] [PATCH v7 00/12] SPI-NAND support Miquel Raynal
2018-09-20 14:06   ` Frieder Schrempf
2018-09-20 14:46     ` Jagan Teki
2018-09-20 14:59       ` Miquel Raynal
2018-09-20 15:22         ` Frieder Schrempf
2018-09-21  8:15         ` Jagan Teki
2018-09-21  8:25           ` Miquel Raynal
2018-09-26 15:14           ` Miquel Raynal

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180906070854.9717-9-miquel.raynal@bootlin.com \
    --to=miquel.raynal@bootlin.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.