kernel: backport upstream mtdpart.c cleanups

Except for renames and line changes the only conflict was in
allocate_partition in handling MTD_WRITEABLE. Hopefully it was handled
correctly.

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
v19.07.3_mercusys_ac12_duma
Rafał Miłecki 7 years ago
parent 4052443a23
commit 8c1e760ab6

@ -0,0 +1,73 @@
From 6080ef6e7c0a0592cbcca11200d879faf65e27d4 Mon Sep 17 00:00:00 2001
From: Jeff Westfahl <jeff.westfahl@ni.com>
Date: Tue, 10 Jan 2017 13:30:17 -0600
Subject: [PATCH] mtd: introduce function max_bad_blocks
If implemented, 'max_bad_blocks' returns the maximum number of bad
blocks to reserve for a MTD. An implementation for NAND is coming soon.
Signed-off-by: Jeff Westfahl <jeff.westfahl@ni.com>
Signed-off-by: Zach Brown <zach.brown@ni.com>
Acked-by: Boris Brezillon <boris.brezillon@free-electron.com>
Acked-by: Brian Norris <computersforpeace@gmail.com>
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
drivers/mtd/mtdpart.c | 10 ++++++++++
include/linux/mtd/mtd.h | 13 +++++++++++++
2 files changed, 23 insertions(+)
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -349,6 +349,14 @@ static const struct mtd_ooblayout_ops pa
.free = part_ooblayout_free,
};
+static int part_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+ struct mtd_part *part = mtd_to_part(mtd);
+
+ return part->master->_max_bad_blocks(part->master,
+ ofs + part->offset, len);
+}
+
static inline void free_partition(struct mtd_part *p)
{
kfree(p->mtd.name);
@@ -475,6 +483,8 @@ static struct mtd_part *allocate_partiti
slave->mtd._block_isbad = part_block_isbad;
if (master->_block_markbad)
slave->mtd._block_markbad = part_block_markbad;
+ if (master->_max_bad_blocks)
+ slave->mtd._max_bad_blocks = part_max_bad_blocks;
if (master->_get_device)
slave->mtd._get_device = part_get_device;
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -322,6 +322,7 @@ struct mtd_info {
int (*_block_isreserved) (struct mtd_info *mtd, loff_t ofs);
int (*_block_isbad) (struct mtd_info *mtd, loff_t ofs);
int (*_block_markbad) (struct mtd_info *mtd, loff_t ofs);
+ int (*_max_bad_blocks) (struct mtd_info *mtd, loff_t ofs, size_t len);
int (*_suspend) (struct mtd_info *mtd);
void (*_resume) (struct mtd_info *mtd);
void (*_reboot) (struct mtd_info *mtd);
@@ -397,6 +398,18 @@ static inline int mtd_oobavail(struct mt
return ops->mode == MTD_OPS_AUTO_OOB ? mtd->oobavail : mtd->oobsize;
}
+static inline int mtd_max_bad_blocks(struct mtd_info *mtd,
+ loff_t ofs, size_t len)
+{
+ if (!mtd->_max_bad_blocks)
+ return -ENOTSUPP;
+
+ if (mtd->size < (len + ofs) || ofs < 0)
+ return -EINVAL;
+
+ return mtd->_max_bad_blocks(mtd, ofs, len);
+}
+
int mtd_wunit_to_pairing_info(struct mtd_info *mtd, int wunit,
struct mtd_pairing_info *info);
int mtd_pairing_info_to_wunit(struct mtd_info *mtd,

@ -0,0 +1,50 @@
From 42e9401bd1467d22c4dc4d2c637347b874e6a80b Mon Sep 17 00:00:00 2001
From: Sascha Hauer <s.hauer@pengutronix.de>
Date: Thu, 9 Feb 2017 11:50:24 +0100
Subject: [PATCH] mtd: Add partition device node to mtd partition devices
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The user visible change here is that mtd partitions get an of_node link
in sysfs.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
drivers/mtd/mtdpart.c | 1 +
drivers/mtd/ofpart.c | 1 +
include/linux/mtd/partitions.h | 1 +
3 files changed, 3 insertions(+)
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -432,6 +432,7 @@ static struct mtd_part *allocate_partiti
slave->mtd.dev.parent = IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER) ?
&master->dev :
master->dev.parent;
+ slave->mtd.dev.of_node = part->of_node;
slave->mtd._read = part_read;
slave->mtd._write = part_write;
--- a/drivers/mtd/ofpart.c
+++ b/drivers/mtd/ofpart.c
@@ -108,6 +108,7 @@ static int parse_ofpart_partitions(struc
parts[i].offset = of_read_number(reg, a_cells);
parts[i].size = of_read_number(reg + a_cells, s_cells);
+ parts[i].of_node = pp;
partname = of_get_property(pp, "label", &len);
if (!partname)
--- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h
@@ -41,6 +41,7 @@ struct mtd_partition {
uint64_t size; /* partition size */
uint64_t offset; /* offset within the master MTD space */
uint32_t mask_flags; /* master MTD flags to mask out for this partition */
+ struct device_node *of_node;
};
#define MTDPART_OFS_RETAIN (-3)

@ -0,0 +1,77 @@
From 1eeef2d7483a7e3f8d2dd2a5b9939b3b814dc549 Mon Sep 17 00:00:00 2001
From: Chris Packham <chris.packham@alliedtelesis.co.nz>
Date: Fri, 9 Jun 2017 15:58:31 +1200
Subject: [PATCH] mtd: handle partitioning on devices with 0 erasesize
erasesize is meaningful for flash devices but for SRAM there is no
concept of an erase block so erasesize is set to 0. When partitioning
these devices instead of ensuring partitions fall on erasesize
boundaries we ensure they fall on writesize boundaries.
Helped-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
Acked-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
drivers/mtd/mtdpart.c | 26 +++++++++++++++++---------
1 file changed, 17 insertions(+), 9 deletions(-)
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -393,8 +393,12 @@ static struct mtd_part *allocate_partiti
const struct mtd_partition *part, int partno,
uint64_t cur_offset)
{
+ int wr_alignment = (master->flags & MTD_NO_ERASE) ? master->writesize:
+ master->erasesize;
struct mtd_part *slave;
+ u32 remainder;
char *name;
+ u64 tmp;
/* allocate the partition structure */
slave = kzalloc(sizeof(*slave), GFP_KERNEL);
@@ -499,10 +503,11 @@ static struct mtd_part *allocate_partiti
if (slave->offset == MTDPART_OFS_APPEND)
slave->offset = cur_offset;
if (slave->offset == MTDPART_OFS_NXTBLK) {
+ tmp = cur_offset;
slave->offset = cur_offset;
- if (mtd_mod_by_eb(cur_offset, master) != 0) {
- /* Round up to next erasesize */
- slave->offset = (mtd_div_by_eb(cur_offset, master) + 1) * master->erasesize;
+ remainder = do_div(tmp, wr_alignment);
+ if (remainder) {
+ slave->offset += wr_alignment - remainder;
printk(KERN_NOTICE "Moving partition %d: "
"0x%012llx -> 0x%012llx\n", partno,
(unsigned long long)cur_offset, (unsigned long long)slave->offset);
@@ -567,19 +572,22 @@ static struct mtd_part *allocate_partiti
slave->mtd.erasesize = master->erasesize;
}
- if ((slave->mtd.flags & MTD_WRITEABLE) &&
- mtd_mod_by_eb(slave->offset, &slave->mtd)) {
+ tmp = slave->offset;
+ remainder = do_div(tmp, wr_alignment);
+ if ((slave->mtd.flags & MTD_WRITEABLE) && remainder) {
/* 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;
- printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
+ printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase/write block boundary -- force read-only\n",
part->name);
}
- if ((slave->mtd.flags & MTD_WRITEABLE) &&
- mtd_mod_by_eb(slave->mtd.size, &slave->mtd)) {
+
+ tmp = slave->mtd.size;
+ remainder = do_div(tmp, wr_alignment);
+ if ((slave->mtd.flags & MTD_WRITEABLE) && remainder) {
slave->mtd.flags &= ~MTD_WRITEABLE;
- printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
+ printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase/write block -- force read-only\n",
part->name);
}

@ -0,0 +1,68 @@
From 01f9c7240a900d5676a8496496f2974dd36996b1 Mon Sep 17 00:00:00 2001
From: Brian Norris <computersforpeace@gmail.com>
Date: Tue, 23 May 2017 07:30:20 +0200
Subject: [PATCH] mtd: partitions: factor out code calling parser
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This code is going to be reused for parsers matched using OF so let's
factor it out to make this easier.
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
Acked-by: Brian Norris <computersforpeace@gmail.com>
---
drivers/mtd/mtdpart.c | 33 ++++++++++++++++++++++++---------
1 file changed, 24 insertions(+), 9 deletions(-)
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -807,6 +807,27 @@ static const char * const default_mtd_pa
NULL
};
+static int mtd_part_do_parse(struct mtd_part_parser *parser,
+ struct mtd_info *master,
+ struct mtd_partitions *pparts,
+ struct mtd_part_parser_data *data)
+{
+ int ret;
+
+ ret = (*parser->parse_fn)(master, &pparts->parts, data);
+ pr_debug("%s: parser %s: %i\n", master->name, parser->name, ret);
+ if (ret <= 0)
+ return ret;
+
+ pr_notice("%d %s partitions found on MTD device %s\n", ret,
+ parser->name, master->name);
+
+ pparts->nr_parts = ret;
+ pparts->parser = parser;
+
+ return ret;
+}
+
/**
* parse_mtd_partitions - parse MTD partitions
* @master: the master partition (describes whole MTD device)
@@ -847,16 +868,10 @@ int parse_mtd_partitions(struct mtd_info
parser ? parser->name : NULL);
if (!parser)
continue;
- ret = (*parser->parse_fn)(master, &pparts->parts, data);
- pr_debug("%s: parser %s: %i\n",
- master->name, parser->name, ret);
- if (ret > 0) {
- printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n",
- ret, parser->name, master->name);
- pparts->nr_parts = ret;
- pparts->parser = parser;
+ ret = mtd_part_do_parse(parser, master, pparts, data);
+ /* Found partitions! */
+ if (ret > 0)
return 0;
- }
mtd_part_parser_put(parser);
/*
* Stash the first error we see; only report it if no parser

@ -0,0 +1,119 @@
From 08263a9ae664b24fa777d20b365601534842b236 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
Date: Wed, 21 Jun 2017 08:26:42 +0200
Subject: [PATCH] mtd: partitions: add helper for deleting partition
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
There are two similar functions handling deletion. One handles single
partition and another the whole MTD flash device. They share (duplicate)
some code so it makes sense to add a small helper for that part.
Function del_mtd_partitions has been moved a bit to keep all deleting
stuff together.
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
drivers/mtd/mtdpart.c | 75 +++++++++++++++++++++++++++++----------------------
1 file changed, 43 insertions(+), 32 deletions(-)
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -363,32 +363,6 @@ static inline void free_partition(struct
kfree(p);
}
-/*
- * This function unregisters and destroy all slave MTD objects which are
- * attached to the given master MTD object.
- */
-
-int del_mtd_partitions(struct mtd_info *master)
-{
- struct mtd_part *slave, *next;
- int ret, err = 0;
-
- 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);
- }
- mutex_unlock(&mtd_partitions_mutex);
-
- return err;
-}
-
static struct mtd_part *allocate_partition(struct mtd_info *master,
const struct mtd_partition *part, int partno,
uint64_t cur_offset)
@@ -675,6 +649,48 @@ int mtd_add_partition(struct mtd_info *m
}
EXPORT_SYMBOL_GPL(mtd_add_partition);
+/**
+ * __mtd_del_partition - delete MTD partition
+ *
+ * @priv: internal MTD struct for partition to be deleted
+ *
+ * This function must be called with the partitions mutex locked.
+ */
+static int __mtd_del_partition(struct mtd_part *priv)
+{
+ int err;
+
+ err = del_mtd_device(&priv->mtd);
+ if (err)
+ return err;
+
+ list_del(&priv->list);
+ free_partition(priv);
+
+ return 0;
+}
+
+/*
+ * This function unregisters and destroy all slave MTD objects which are
+ * attached to the given master MTD object.
+ */
+int del_mtd_partitions(struct mtd_info *master)
+{
+ struct mtd_part *slave, *next;
+ int ret, err = 0;
+
+ mutex_lock(&mtd_partitions_mutex);
+ list_for_each_entry_safe(slave, next, &mtd_partitions, list)
+ if (slave->master == master) {
+ ret = __mtd_del_partition(slave);
+ if (ret < 0)
+ err = ret;
+ }
+ mutex_unlock(&mtd_partitions_mutex);
+
+ return err;
+}
+
int mtd_del_partition(struct mtd_info *master, int partno)
{
struct mtd_part *slave, *next;
@@ -686,12 +702,7 @@ int mtd_del_partition(struct mtd_info *m
(slave->mtd.index == partno)) {
sysfs_remove_files(&slave->mtd.dev.kobj,
mtd_partition_attrs);
- ret = del_mtd_device(&slave->mtd);
- if (ret < 0)
- break;
-
- list_del(&slave->list);
- free_partition(slave);
+ ret = __mtd_del_partition(slave);
break;
}
mutex_unlock(&mtd_partitions_mutex);

@ -0,0 +1,45 @@
From c5ceaba74083daf619bdb34d4871e297a177eebf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
Date: Wed, 21 Jun 2017 08:26:43 +0200
Subject: [PATCH] mtd: partitions: remove sysfs files when deleting all
master's partitions
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
When support for sysfs "offset" file was added it missed to update the
del_mtd_partitions function. It deletes partitions just like
mtd_del_partition does so both should also take care of removing sysfs
files.
This change moves sysfs_remove_files call to the shared function to fix
this issue.
Fixes: a62c24d755291 ("mtd: part: Add sysfs variable for offset of partition")
Cc: Dan Ehrenberg <dehrenberg@chromium.org>
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
drivers/mtd/mtdpart.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -660,6 +660,8 @@ static int __mtd_del_partition(struct mt
{
int err;
+ sysfs_remove_files(&priv->mtd.dev.kobj, mtd_partition_attrs);
+
err = del_mtd_device(&priv->mtd);
if (err)
return err;
@@ -700,8 +702,6 @@ int mtd_del_partition(struct mtd_info *m
list_for_each_entry_safe(slave, next, &mtd_partitions, list)
if ((slave->master == master) &&
(slave->mtd.index == partno)) {
- sysfs_remove_files(&slave->mtd.dev.kobj,
- mtd_partition_attrs);
ret = __mtd_del_partition(slave);
break;
}

@ -0,0 +1,606 @@
From 0a9d72b69da6d8dae1abd7990c6c4c749846ef3e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
Date: Wed, 21 Jun 2017 08:26:44 +0200
Subject: [PATCH] mtd: partitions: rename "master" to the "parent" where
appropriate
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This prepares mtd subsystem for the new feature: subpartitions. In some
cases flash device partition can be a container with extra subpartitions
(volumes).
So far there was a flat structure implemented. One master (flash device)
could be partitioned into few partitions. Every partition got its master
and it was enough to get things running.
To support subpartitions we need to store pointer to the parent for each
partition. This is required to implement more natural tree structure and
handle all recursion and offsets calculation.
To make code consistent this patch renamed "master" to the "parent" in
places where we can be dealing with subpartitions.
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
drivers/mtd/mtdpart.c | 204 ++++++++++++++++++++++++++------------------------
1 file changed, 105 insertions(+), 99 deletions(-)
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -37,10 +37,16 @@
static LIST_HEAD(mtd_partitions);
static DEFINE_MUTEX(mtd_partitions_mutex);
-/* Our partition node structure */
+/**
+ * struct mtd_part - our partition node structure
+ *
+ * @mtd: struct holding partition details
+ * @parent: parent mtd - flash device or another partition
+ * @offset: partition offset relative to the *flash device*
+ */
struct mtd_part {
struct mtd_info mtd;
- struct mtd_info *master;
+ struct mtd_info *parent;
uint64_t offset;
struct list_head list;
};
@@ -67,15 +73,15 @@ static int part_read(struct mtd_info *mt
struct mtd_ecc_stats stats;
int res;
- stats = part->master->ecc_stats;
- res = part->master->_read(part->master, from + part->offset, len,
+ stats = part->parent->ecc_stats;
+ res = part->parent->_read(part->parent, from + part->offset, len,
retlen, buf);
if (unlikely(mtd_is_eccerr(res)))
mtd->ecc_stats.failed +=
- part->master->ecc_stats.failed - stats.failed;
+ part->parent->ecc_stats.failed - stats.failed;
else
mtd->ecc_stats.corrected +=
- part->master->ecc_stats.corrected - stats.corrected;
+ part->parent->ecc_stats.corrected - stats.corrected;
return res;
}
@@ -84,7 +90,7 @@ static int part_point(struct mtd_info *m
{
struct mtd_part *part = mtd_to_part(mtd);
- return part->master->_point(part->master, from + part->offset, len,
+ return part->parent->_point(part->parent, from + part->offset, len,
retlen, virt, phys);
}
@@ -92,7 +98,7 @@ static int part_unpoint(struct mtd_info
{
struct mtd_part *part = mtd_to_part(mtd);
- return part->master->_unpoint(part->master, from + part->offset, len);
+ return part->parent->_unpoint(part->parent, from + part->offset, len);
}
static unsigned long part_get_unmapped_area(struct mtd_info *mtd,
@@ -103,7 +109,7 @@ static unsigned long part_get_unmapped_a
struct mtd_part *part = mtd_to_part(mtd);
offset += part->offset;
- return part->master->_get_unmapped_area(part->master, len, offset,
+ return part->parent->_get_unmapped_area(part->parent, len, offset,
flags);
}
@@ -132,7 +138,7 @@ static int part_read_oob(struct mtd_info
return -EINVAL;
}
- res = part->master->_read_oob(part->master, from + part->offset, ops);
+ res = part->parent->_read_oob(part->parent, from + part->offset, ops);
if (unlikely(res)) {
if (mtd_is_bitflip(res))
mtd->ecc_stats.corrected++;
@@ -146,7 +152,7 @@ static int part_read_user_prot_reg(struc
size_t len, size_t *retlen, u_char *buf)
{
struct mtd_part *part = mtd_to_part(mtd);
- return part->master->_read_user_prot_reg(part->master, from, len,
+ return part->parent->_read_user_prot_reg(part->parent, from, len,
retlen, buf);
}
@@ -154,7 +160,7 @@ static int part_get_user_prot_info(struc
size_t *retlen, struct otp_info *buf)
{
struct mtd_part *part = mtd_to_part(mtd);
- return part->master->_get_user_prot_info(part->master, len, retlen,
+ return part->parent->_get_user_prot_info(part->parent, len, retlen,
buf);
}
@@ -162,7 +168,7 @@ static int part_read_fact_prot_reg(struc
size_t len, size_t *retlen, u_char *buf)
{
struct mtd_part *part = mtd_to_part(mtd);
- return part->master->_read_fact_prot_reg(part->master, from, len,
+ return part->parent->_read_fact_prot_reg(part->parent, from, len,
retlen, buf);
}
@@ -170,7 +176,7 @@ static int part_get_fact_prot_info(struc
size_t *retlen, struct otp_info *buf)
{
struct mtd_part *part = mtd_to_part(mtd);
- return part->master->_get_fact_prot_info(part->master, len, retlen,
+ return part->parent->_get_fact_prot_info(part->parent, len, retlen,
buf);
}
@@ -178,7 +184,7 @@ static int part_write(struct mtd_info *m
size_t *retlen, const u_char *buf)
{
struct mtd_part *part = mtd_to_part(mtd);
- return part->master->_write(part->master, to + part->offset, len,
+ return part->parent->_write(part->parent, to + part->offset, len,
retlen, buf);
}
@@ -186,7 +192,7 @@ static int part_panic_write(struct mtd_i
size_t *retlen, const u_char *buf)
{
struct mtd_part *part = mtd_to_part(mtd);
- return part->master->_panic_write(part->master, to + part->offset, len,
+ return part->parent->_panic_write(part->parent, to + part->offset, len,
retlen, buf);
}
@@ -199,14 +205,14 @@ static int part_write_oob(struct mtd_inf
return -EINVAL;
if (ops->datbuf && to + ops->len > mtd->size)
return -EINVAL;
- return part->master->_write_oob(part->master, to + part->offset, ops);
+ return part->parent->_write_oob(part->parent, to + part->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 = mtd_to_part(mtd);
- return part->master->_write_user_prot_reg(part->master, from, len,
+ return part->parent->_write_user_prot_reg(part->parent, from, len,
retlen, buf);
}
@@ -214,14 +220,14 @@ static int part_lock_user_prot_reg(struc
size_t len)
{
struct mtd_part *part = mtd_to_part(mtd);
- return part->master->_lock_user_prot_reg(part->master, from, len);
+ return part->parent->_lock_user_prot_reg(part->parent, from, len);
}
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 = mtd_to_part(mtd);
- return part->master->_writev(part->master, vecs, count,
+ return part->parent->_writev(part->parent, vecs, count,
to + part->offset, retlen);
}
@@ -231,7 +237,7 @@ static int part_erase(struct mtd_info *m
int ret;
instr->addr += part->offset;
- ret = part->master->_erase(part->master, instr);
+ ret = part->parent->_erase(part->parent, instr);
if (ret) {
if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
instr->fail_addr -= part->offset;
@@ -257,51 +263,51 @@ EXPORT_SYMBOL_GPL(mtd_erase_callback);
static int part_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
struct mtd_part *part = mtd_to_part(mtd);
- return part->master->_lock(part->master, ofs + part->offset, len);
+ return part->parent->_lock(part->parent, ofs + part->offset, len);
}
static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
struct mtd_part *part = mtd_to_part(mtd);
- return part->master->_unlock(part->master, ofs + part->offset, len);
+ return part->parent->_unlock(part->parent, ofs + part->offset, len);
}
static int part_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
struct mtd_part *part = mtd_to_part(mtd);
- return part->master->_is_locked(part->master, ofs + part->offset, len);
+ return part->parent->_is_locked(part->parent, ofs + part->offset, len);
}
static void part_sync(struct mtd_info *mtd)
{
struct mtd_part *part = mtd_to_part(mtd);
- part->master->_sync(part->master);
+ part->parent->_sync(part->parent);
}
static int part_suspend(struct mtd_info *mtd)
{
struct mtd_part *part = mtd_to_part(mtd);
- return part->master->_suspend(part->master);
+ return part->parent->_suspend(part->parent);
}
static void part_resume(struct mtd_info *mtd)
{
struct mtd_part *part = mtd_to_part(mtd);
- part->master->_resume(part->master);
+ part->parent->_resume(part->parent);
}
static int part_block_isreserved(struct mtd_info *mtd, loff_t ofs)
{
struct mtd_part *part = mtd_to_part(mtd);
ofs += part->offset;
- return part->master->_block_isreserved(part->master, ofs);
+ return part->parent->_block_isreserved(part->parent, ofs);
}
static int part_block_isbad(struct mtd_info *mtd, loff_t ofs)
{
struct mtd_part *part = mtd_to_part(mtd);
ofs += part->offset;
- return part->master->_block_isbad(part->master, ofs);
+ return part->parent->_block_isbad(part->parent, ofs);
}
static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
@@ -310,7 +316,7 @@ static int part_block_markbad(struct mtd
int res;
ofs += part->offset;
- res = part->master->_block_markbad(part->master, ofs);
+ res = part->parent->_block_markbad(part->parent, ofs);
if (!res)
mtd->ecc_stats.badblocks++;
return res;
@@ -319,13 +325,13 @@ static int part_block_markbad(struct mtd
static int part_get_device(struct mtd_info *mtd)
{
struct mtd_part *part = mtd_to_part(mtd);
- return part->master->_get_device(part->master);
+ return part->parent->_get_device(part->parent);
}
static void part_put_device(struct mtd_info *mtd)
{
struct mtd_part *part = mtd_to_part(mtd);
- part->master->_put_device(part->master);
+ part->parent->_put_device(part->parent);
}
static int part_ooblayout_ecc(struct mtd_info *mtd, int section,
@@ -333,7 +339,7 @@ static int part_ooblayout_ecc(struct mtd
{
struct mtd_part *part = mtd_to_part(mtd);
- return mtd_ooblayout_ecc(part->master, section, oobregion);
+ return mtd_ooblayout_ecc(part->parent, section, oobregion);
}
static int part_ooblayout_free(struct mtd_info *mtd, int section,
@@ -341,7 +347,7 @@ static int part_ooblayout_free(struct mt
{
struct mtd_part *part = mtd_to_part(mtd);
- return mtd_ooblayout_free(part->master, section, oobregion);
+ return mtd_ooblayout_free(part->parent, section, oobregion);
}
static const struct mtd_ooblayout_ops part_ooblayout_ops = {
@@ -353,7 +359,7 @@ static int part_max_bad_blocks(struct mt
{
struct mtd_part *part = mtd_to_part(mtd);
- return part->master->_max_bad_blocks(part->master,
+ return part->parent->_max_bad_blocks(part->parent,
ofs + part->offset, len);
}
@@ -363,12 +369,12 @@ static inline void free_partition(struct
kfree(p);
}
-static struct mtd_part *allocate_partition(struct mtd_info *master,
+static struct mtd_part *allocate_partition(struct mtd_info *parent,
const struct mtd_partition *part, int partno,
uint64_t cur_offset)
{
- int wr_alignment = (master->flags & MTD_NO_ERASE) ? master->writesize:
- master->erasesize;
+ int wr_alignment = (parent->flags & MTD_NO_ERASE) ? parent->writesize:
+ parent->erasesize;
struct mtd_part *slave;
u32 remainder;
char *name;
@@ -379,25 +385,25 @@ static struct mtd_part *allocate_partiti
name = kstrdup(part->name, GFP_KERNEL);
if (!name || !slave) {
printk(KERN_ERR"memory allocation error while creating partitions for \"%s\"\n",
- master->name);
+ parent->name);
kfree(name);
kfree(slave);
return ERR_PTR(-ENOMEM);
}
/* set up the MTD object for this partition */
- slave->mtd.type = master->type;
- slave->mtd.flags = master->flags & ~part->mask_flags;
+ slave->mtd.type = parent->type;
+ slave->mtd.flags = parent->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->mtd.pairing = master->pairing;
+ slave->mtd.writesize = parent->writesize;
+ slave->mtd.writebufsize = parent->writebufsize;
+ slave->mtd.oobsize = parent->oobsize;
+ slave->mtd.oobavail = parent->oobavail;
+ slave->mtd.subpage_sft = parent->subpage_sft;
+ slave->mtd.pairing = parent->pairing;
slave->mtd.name = name;
- slave->mtd.owner = master->owner;
+ slave->mtd.owner = parent->owner;
/* NOTE: Historically, we didn't arrange MTDs as a tree out of
* concern for showing the same data in multiple partitions.
@@ -408,70 +414,70 @@ static struct mtd_part *allocate_partiti
* distinguish between the master and the partition in sysfs.
*/
slave->mtd.dev.parent = IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER) ?
- &master->dev :
- master->dev.parent;
+ &parent->dev :
+ parent->dev.parent;
slave->mtd.dev.of_node = part->of_node;
slave->mtd._read = part_read;
slave->mtd._write = part_write;
- if (master->_panic_write)
+ if (parent->_panic_write)
slave->mtd._panic_write = part_panic_write;
- if (master->_point && master->_unpoint) {
+ if (parent->_point && parent->_unpoint) {
slave->mtd._point = part_point;
slave->mtd._unpoint = part_unpoint;
}
- if (master->_get_unmapped_area)
+ if (parent->_get_unmapped_area)
slave->mtd._get_unmapped_area = part_get_unmapped_area;
- if (master->_read_oob)
+ if (parent->_read_oob)
slave->mtd._read_oob = part_read_oob;
- if (master->_write_oob)
+ if (parent->_write_oob)
slave->mtd._write_oob = part_write_oob;
- if (master->_read_user_prot_reg)
+ if (parent->_read_user_prot_reg)
slave->mtd._read_user_prot_reg = part_read_user_prot_reg;
- if (master->_read_fact_prot_reg)
+ if (parent->_read_fact_prot_reg)
slave->mtd._read_fact_prot_reg = part_read_fact_prot_reg;
- if (master->_write_user_prot_reg)
+ if (parent->_write_user_prot_reg)
slave->mtd._write_user_prot_reg = part_write_user_prot_reg;
- if (master->_lock_user_prot_reg)
+ if (parent->_lock_user_prot_reg)
slave->mtd._lock_user_prot_reg = part_lock_user_prot_reg;
- if (master->_get_user_prot_info)
+ if (parent->_get_user_prot_info)
slave->mtd._get_user_prot_info = part_get_user_prot_info;
- if (master->_get_fact_prot_info)
+ if (parent->_get_fact_prot_info)
slave->mtd._get_fact_prot_info = part_get_fact_prot_info;
- if (master->_sync)
+ if (parent->_sync)
slave->mtd._sync = part_sync;
- if (!partno && !master->dev.class && master->_suspend &&
- master->_resume) {
+ if (!partno && !parent->dev.class && parent->_suspend &&
+ parent->_resume) {
slave->mtd._suspend = part_suspend;
slave->mtd._resume = part_resume;
}
- if (master->_writev)
+ if (parent->_writev)
slave->mtd._writev = part_writev;
- if (master->_lock)
+ if (parent->_lock)
slave->mtd._lock = part_lock;
- if (master->_unlock)
+ if (parent->_unlock)
slave->mtd._unlock = part_unlock;
- if (master->_is_locked)
+ if (parent->_is_locked)
slave->mtd._is_locked = part_is_locked;
- if (master->_block_isreserved)
+ if (parent->_block_isreserved)
slave->mtd._block_isreserved = part_block_isreserved;
- if (master->_block_isbad)
+ if (parent->_block_isbad)
slave->mtd._block_isbad = part_block_isbad;
- if (master->_block_markbad)
+ if (parent->_block_markbad)
slave->mtd._block_markbad = part_block_markbad;
- if (master->_max_bad_blocks)
+ if (parent->_max_bad_blocks)
slave->mtd._max_bad_blocks = part_max_bad_blocks;
- if (master->_get_device)
+ if (parent->_get_device)
slave->mtd._get_device = part_get_device;
- if (master->_put_device)
+ if (parent->_put_device)
slave->mtd._put_device = part_put_device;
slave->mtd._erase = part_erase;
- slave->master = master;
+ slave->parent = parent;
slave->offset = part->offset;
if (slave->offset == MTDPART_OFS_APPEND)
@@ -489,25 +495,25 @@ static struct mtd_part *allocate_partiti
}
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
+ if (parent->size - slave->offset >= slave->mtd.size) {
+ slave->mtd.size = parent->size - slave->offset
- slave->mtd.size;
} else {
printk(KERN_ERR "mtd partition \"%s\" doesn't have enough space: %#llx < %#llx, disabled\n",
- part->name, master->size - slave->offset,
+ part->name, parent->size - slave->offset,
slave->mtd.size);
/* register to preserve ordering */
goto out_register;
}
}
if (slave->mtd.size == MTDPART_SIZ_FULL)
- slave->mtd.size = master->size - slave->offset;
+ slave->mtd.size = parent->size - slave->offset;
printk(KERN_NOTICE "0x%012llx-0x%012llx : \"%s\"\n", (unsigned long long)slave->offset,
(unsigned long long)(slave->offset + slave->mtd.size), slave->mtd.name);
/* let's do some sanity checks */
- if (slave->offset >= master->size) {
+ if (slave->offset >= parent->size) {
/* let's register it anyway to preserve ordering */
slave->offset = 0;
slave->mtd.size = 0;
@@ -515,16 +521,16 @@ static struct mtd_part *allocate_partiti
part->name);
goto out_register;
}
- if (slave->offset + slave->mtd.size > master->size) {
- slave->mtd.size = master->size - slave->offset;
+ if (slave->offset + slave->mtd.size > parent->size) {
+ slave->mtd.size = parent->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, parent->name, (unsigned long long)slave->mtd.size);
}
- if (master->numeraseregions > 1) {
+ if (parent->numeraseregions > 1) {
/* Deal with variable erase size stuff */
- int i, max = master->numeraseregions;
+ int i, max = parent->numeraseregions;
u64 end = slave->offset + slave->mtd.size;
- struct mtd_erase_region_info *regions = master->eraseregions;
+ struct mtd_erase_region_info *regions = parent->eraseregions;
/* Find the first erase regions which is part of this
* partition. */
@@ -543,7 +549,7 @@ static struct mtd_part *allocate_partiti
BUG_ON(slave->mtd.erasesize == 0);
} else {
/* Single erase size */
- slave->mtd.erasesize = master->erasesize;
+ slave->mtd.erasesize = parent->erasesize;
}
tmp = slave->offset;
@@ -566,17 +572,17 @@ static struct mtd_part *allocate_partiti
}
mtd_set_ooblayout(&slave->mtd, &part_ooblayout_ops);
- slave->mtd.ecc_step_size = master->ecc_step_size;
- slave->mtd.ecc_strength = master->ecc_strength;
- slave->mtd.bitflip_threshold = master->bitflip_threshold;
+ slave->mtd.ecc_step_size = parent->ecc_step_size;
+ slave->mtd.ecc_strength = parent->ecc_strength;
+ slave->mtd.bitflip_threshold = parent->bitflip_threshold;
- if (master->_block_isbad) {
+ if (parent->_block_isbad) {
uint64_t offs = 0;
while (offs < slave->mtd.size) {
- if (mtd_block_isreserved(master, offs + slave->offset))
+ if (mtd_block_isreserved(parent, offs + slave->offset))
slave->mtd.ecc_stats.bbtblocks++;
- else if (mtd_block_isbad(master, offs + slave->offset))
+ else if (mtd_block_isbad(parent, offs + slave->offset))
slave->mtd.ecc_stats.badblocks++;
offs += slave->mtd.erasesize;
}
@@ -610,7 +616,7 @@ static int mtd_add_partition_attrs(struc
return ret;
}
-int mtd_add_partition(struct mtd_info *master, const char *name,
+int mtd_add_partition(struct mtd_info *parent, const char *name,
long long offset, long long length)
{
struct mtd_partition part;
@@ -623,7 +629,7 @@ int mtd_add_partition(struct mtd_info *m
return -EINVAL;
if (length == MTDPART_SIZ_FULL)
- length = master->size - offset;
+ length = parent->size - offset;
if (length <= 0)
return -EINVAL;
@@ -633,7 +639,7 @@ int mtd_add_partition(struct mtd_info *m
part.size = length;
part.offset = offset;
- new = allocate_partition(master, &part, -1, offset);
+ new = allocate_partition(parent, &part, -1, offset);
if (IS_ERR(new))
return PTR_ERR(new);
@@ -683,7 +689,7 @@ int del_mtd_partitions(struct mtd_info *
mutex_lock(&mtd_partitions_mutex);
list_for_each_entry_safe(slave, next, &mtd_partitions, list)
- if (slave->master == master) {
+ if (slave->parent == master) {
ret = __mtd_del_partition(slave);
if (ret < 0)
err = ret;
@@ -700,7 +706,7 @@ int mtd_del_partition(struct mtd_info *m
mutex_lock(&mtd_partitions_mutex);
list_for_each_entry_safe(slave, next, &mtd_partitions, list)
- if ((slave->master == master) &&
+ if ((slave->parent == master) &&
(slave->mtd.index == partno)) {
ret = __mtd_del_partition(slave);
break;
@@ -933,6 +939,6 @@ uint64_t mtd_get_device_size(const struc
if (!mtd_is_partition(mtd))
return mtd->size;
- return mtd_to_part(mtd)->master->size;
+ return mtd_to_part(mtd)->parent->size;
}
EXPORT_SYMBOL_GPL(mtd_get_device_size);

@ -116,7 +116,7 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
#include <linux/err.h>
#include "mtdcore.h"
@@ -779,6 +780,42 @@ void deregister_mtd_parser(struct mtd_pa
@@ -815,6 +816,42 @@ void deregister_mtd_parser(struct mtd_pa
EXPORT_SYMBOL_GPL(deregister_mtd_parser);
/*
@ -159,7 +159,7 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
* Do not forget to update 'parse_mtd_partitions()' kerneldoc comment if you
* are changing this array!
*/
@@ -815,6 +852,13 @@ int parse_mtd_partitions(struct mtd_info
@@ -872,6 +909,13 @@ int parse_mtd_partitions(struct mtd_info
{
struct mtd_part_parser *parser;
int ret, err = 0;
@ -173,7 +173,7 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
if (!types)
types = default_mtd_part_types;
@@ -846,6 +890,7 @@ int parse_mtd_partitions(struct mtd_info
@@ -897,6 +941,7 @@ int parse_mtd_partitions(struct mtd_info
if (ret < 0 && !err)
err = ret;
}

@ -39,7 +39,7 @@
/* Our partition linked list */
static LIST_HEAD(mtd_partitions);
@@ -46,6 +48,8 @@ struct mtd_part {
@@ -52,6 +54,8 @@ struct mtd_part {
struct list_head list;
};
@ -48,15 +48,15 @@
/*
* Given a pointer to the MTD object in the mtd_part structure, we can retrieve
* the pointer to that structure.
@@ -650,6 +654,7 @@ int mtd_add_partition(struct mtd_info *m
@@ -649,6 +653,7 @@ int mtd_add_partition(struct mtd_info *p
mutex_unlock(&mtd_partitions_mutex);
add_mtd_device(&new->mtd);
+ mtd_partition_split(master, new);
+ mtd_partition_split(parent, new);
mtd_add_partition_attrs(new);
@@ -682,6 +687,35 @@ int mtd_del_partition(struct mtd_info *m
@@ -718,6 +723,35 @@ int mtd_del_partition(struct mtd_info *m
}
EXPORT_SYMBOL_GPL(mtd_del_partition);
@ -92,7 +92,7 @@
/*
* This function, given a master MTD object and a partition table, creates
* and registers slave MTD objects which are bound to the master according to
@@ -713,6 +747,7 @@ int add_mtd_partitions(struct mtd_info *
@@ -749,6 +783,7 @@ int add_mtd_partitions(struct mtd_info *
mutex_unlock(&mtd_partitions_mutex);
add_mtd_device(&slave->mtd);
@ -102,7 +102,7 @@
cur_offset = slave->offset + slave->mtd.size;
--- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h
@@ -101,5 +101,7 @@ int mtd_add_partition(struct mtd_info *m
@@ -102,5 +102,7 @@ int mtd_add_partition(struct mtd_info *m
long long offset, long long length);
int mtd_del_partition(struct mtd_info *master, int partno);
uint64_t mtd_get_device_size(const struct mtd_info *mtd);

@ -11,7 +11,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -945,6 +945,62 @@ void mtd_part_parser_cleanup(struct mtd_
@@ -996,6 +996,62 @@ void mtd_part_parser_cleanup(struct mtd_
}
}
@ -76,7 +76,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
struct mtd_part *part;
--- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h
@@ -60,11 +60,14 @@ struct mtd_part_parser_data {
@@ -61,11 +61,14 @@ struct mtd_part_parser_data {
unsigned long origin;
};
@ -92,7 +92,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
struct mtd_part_parser {
struct list_head list;
struct module *owner;
@@ -72,6 +75,7 @@ struct mtd_part_parser {
@@ -73,6 +76,7 @@ struct mtd_part_parser {
int (*parse_fn)(struct mtd_info *, const struct mtd_partition **,
struct mtd_part_parser_data *);
void (*cleanup)(const struct mtd_partition *pparts, int nr_parts);
@ -100,7 +100,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
};
/* Container for passing around a set of parsed partitions */
@@ -104,4 +108,9 @@ uint64_t mtd_get_device_size(const struc
@@ -105,4 +109,9 @@ uint64_t mtd_get_device_size(const struc
extern void __weak arch_split_mtd_part(struct mtd_info *master,
const char *name, int offset, int size);

@ -1,6 +1,6 @@
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -687,6 +687,36 @@ int mtd_del_partition(struct mtd_info *m
@@ -723,6 +723,36 @@ int mtd_del_partition(struct mtd_info *m
}
EXPORT_SYMBOL_GPL(mtd_del_partition);
@ -23,7 +23,7 @@
+ /* adjust partition offsets */
+ parts[i].offset += slave->offset;
+
+ mtd_add_partition(slave->master,
+ mtd_add_partition(slave->parent,
+ parts[i].name,
+ parts[i].offset,
+ parts[i].size);
@ -37,7 +37,7 @@
#ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
#define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME
#else
@@ -695,6 +725,7 @@ EXPORT_SYMBOL_GPL(mtd_del_partition);
@@ -731,6 +761,7 @@ EXPORT_SYMBOL_GPL(mtd_del_partition);
static void split_firmware(struct mtd_info *master, struct mtd_part *part)
{
@ -45,7 +45,7 @@
}
void __weak arch_split_mtd_part(struct mtd_info *master, const char *name,
@@ -709,6 +740,12 @@ static void mtd_partition_split(struct m
@@ -745,6 +776,12 @@ static void mtd_partition_split(struct m
if (rootfs_found)
return;
@ -60,7 +60,7 @@
split_firmware(master, part);
--- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h
@@ -66,6 +66,8 @@ struct mtd_part_parser_data {
@@ -67,6 +67,8 @@ struct mtd_part_parser_data {
enum mtd_parser_type {
MTD_PARSER_TYPE_DEVICE = 0,

@ -1,6 +1,6 @@
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -717,6 +717,17 @@ run_parsers_by_type(struct mtd_part *sla
@@ -753,6 +753,17 @@ run_parsers_by_type(struct mtd_part *sla
return nr_parts;
}
@ -18,7 +18,7 @@
#ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
#define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME
#else
@@ -1055,6 +1066,24 @@ int mtd_is_partition(const struct mtd_in
@@ -1106,6 +1117,24 @@ int mtd_is_partition(const struct mtd_in
}
EXPORT_SYMBOL_GPL(mtd_is_partition);
@ -27,7 +27,7 @@
+ if (!mtd_is_partition(mtd))
+ return (struct mtd_info *)mtd;
+
+ return mtd_to_part(mtd)->master;
+ return mtd_to_part(mtd)->parent;
+}
+EXPORT_SYMBOL_GPL(mtdpart_get_master);
+
@ -45,7 +45,7 @@
{
--- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h
@@ -106,6 +106,8 @@ int mtd_is_partition(const struct mtd_in
@@ -107,6 +107,8 @@ int mtd_is_partition(const struct mtd_in
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);
@ -56,7 +56,7 @@
const char *name, int offset, int size);
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -472,6 +472,24 @@ static inline uint32_t mtd_mod_by_eb(uin
@@ -485,6 +485,24 @@ static inline uint32_t mtd_mod_by_eb(uin
return do_div(sz, mtd->erasesize);
}

@ -8,7 +8,7 @@
struct mtd_partition {
const char *name; /* identifier string */
@@ -49,7 +50,6 @@ struct mtd_partition {
@@ -50,7 +51,6 @@ struct mtd_partition {
#define MTDPART_SIZ_FULL (0)

@ -9,7 +9,7 @@
/* Our partition linked list */
static LIST_HEAD(mtd_partitions);
static DEFINE_MUTEX(mtd_partitions_mutex);
@@ -235,13 +237,61 @@ static int part_erase(struct mtd_info *m
@@ -241,13 +243,61 @@ static int part_erase(struct mtd_info *m
struct mtd_part *part = mtd_to_part(mtd);
int ret;
@ -19,33 +19,33 @@
+ size_t readlen = 0;
+ u64 mtd_ofs;
+
+ instr->erase_buf = kmalloc(part->master->erasesize, GFP_ATOMIC);
+ instr->erase_buf = kmalloc(part->parent->erasesize, GFP_ATOMIC);
+ if (!instr->erase_buf)
+ return -ENOMEM;
+
+ mtd_ofs = part->offset + instr->addr;
+ instr->erase_buf_ofs = do_div(mtd_ofs, part->master->erasesize);
+ instr->erase_buf_ofs = do_div(mtd_ofs, part->parent->erasesize);
+
+ if (instr->erase_buf_ofs > 0) {
+ instr->addr -= instr->erase_buf_ofs;
+ ret = mtd_read(part->master,
+ ret = mtd_read(part->parent,
+ instr->addr + part->offset,
+ part->master->erasesize,
+ part->parent->erasesize,
+ &readlen, instr->erase_buf);
+
+ instr->len += instr->erase_buf_ofs;
+ instr->partial_start = true;
+ } else {
+ mtd_ofs = part->offset + part->mtd.size;
+ instr->erase_buf_ofs = part->master->erasesize -
+ do_div(mtd_ofs, part->master->erasesize);
+ instr->erase_buf_ofs = part->parent->erasesize -
+ do_div(mtd_ofs, part->parent->erasesize);
+
+ if (instr->erase_buf_ofs > 0) {
+ instr->len += instr->erase_buf_ofs;
+ ret = mtd_read(part->master,
+ ret = mtd_read(part->parent,
+ part->offset + instr->addr +
+ instr->len - part->master->erasesize,
+ part->master->erasesize, &readlen,
+ instr->len - part->parent->erasesize,
+ part->parent->erasesize, &readlen,
+ instr->erase_buf);
+ } else {
+ ret = 0;
@ -59,7 +59,7 @@
+ }
+
instr->addr += part->offset;
ret = part->master->_erase(part->master, instr);
ret = part->parent->_erase(part->parent, instr);
if (ret) {
if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
instr->fail_addr -= part->offset;
@ -71,7 +71,7 @@
return ret;
}
@@ -249,6 +299,25 @@ void mtd_erase_callback(struct erase_inf
@@ -255,6 +305,25 @@ void mtd_erase_callback(struct erase_inf
{
if (instr->mtd->_erase == part_erase) {
struct mtd_part *part = mtd_to_part(instr->mtd);
@ -79,17 +79,17 @@
+
+ if (instr->mtd->flags & MTD_ERASE_PARTIAL) {
+ if (instr->partial_start) {
+ part->master->_write(part->master,
+ part->parent->_write(part->parent,
+ instr->addr, instr->erase_buf_ofs,
+ &wrlen, instr->erase_buf);
+ instr->addr += instr->erase_buf_ofs;
+ } else {
+ instr->len -= instr->erase_buf_ofs;
+ part->master->_write(part->master,
+ part->parent->_write(part->parent,
+ instr->addr + instr->len,
+ instr->erase_buf_ofs, &wrlen,
+ instr->erase_buf +
+ part->master->erasesize -
+ part->parent->erasesize -
+ instr->erase_buf_ofs);
+ }
+ kfree(instr->erase_buf);
@ -97,30 +97,32 @@
if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
instr->fail_addr -= part->offset;
@@ -564,17 +633,20 @@ static struct mtd_part *allocate_partiti
if ((slave->mtd.flags & MTD_WRITEABLE) &&
mtd_mod_by_eb(slave->offset, &slave->mtd)) {
@@ -561,19 +630,22 @@ static struct mtd_part *allocate_partiti
remainder = do_div(tmp, wr_alignment);
if ((slave->mtd.flags & MTD_WRITEABLE) && remainder) {
/* 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;
- printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
- printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase/write block boundary -- force read-only\n",
- part->name);
+ slave->mtd.flags |= MTD_ERASE_PARTIAL;
+ if (((u32) slave->mtd.size) > master->erasesize)
+ if (((u32)slave->mtd.size) > parent->erasesize)
+ slave->mtd.flags &= ~MTD_WRITEABLE;
+ else
+ slave->mtd.erasesize = slave->mtd.size;
}
if ((slave->mtd.flags & MTD_WRITEABLE) &&
- mtd_mod_by_eb(slave->mtd.size, &slave->mtd)) {
- tmp = slave->mtd.size;
+ tmp = slave->offset + slave->mtd.size;
remainder = do_div(tmp, wr_alignment);
if ((slave->mtd.flags & MTD_WRITEABLE) && remainder) {
- slave->mtd.flags &= ~MTD_WRITEABLE;
- printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
- printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase/write block -- force read-only\n",
- part->name);
+ mtd_mod_by_eb(slave->offset + slave->mtd.size, &slave->mtd)) {
+ slave->mtd.flags |= MTD_ERASE_PARTIAL;
+
+ if ((u32) slave->mtd.size > master->erasesize)
+ if ((u32)slave->mtd.size > parent->erasesize)
+ slave->mtd.flags &= ~MTD_WRITEABLE;
+ else
+ slave->mtd.erasesize = slave->mtd.size;

@ -1,20 +1,20 @@
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -337,7 +337,16 @@ static int part_lock(struct mtd_info *mt
@@ -343,7 +343,16 @@ static int part_lock(struct mtd_info *mt
static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
struct mtd_part *part = mtd_to_part(mtd);
- return part->master->_unlock(part->master, ofs + part->offset, len);
- return part->parent->_unlock(part->parent, ofs + part->offset, len);
+
+ ofs += part->offset;
+
+ if (mtd->flags & MTD_ERASE_PARTIAL) {
+ /* round up len to next erasesize and round down offset to prev block */
+ len = (mtd_div_by_eb(len, part->master) + 1) * part->master->erasesize;
+ ofs &= ~(part->master->erasesize - 1);
+ len = (mtd_div_by_eb(len, part->parent) + 1) * part->parent->erasesize;
+ ofs &= ~(part->parent->erasesize - 1);
+ }
+
+ return part->master->_unlock(part->master, ofs, len);
+ return part->parent->_unlock(part->parent, ofs, len);
}
static int part_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)

Loading…
Cancel
Save