allocate_partition() checks a partition offset and size against the
erase size of its master. A device which cannot erase has no erase
size, so the check divides by zero and "mtd list" ends in
### ERROR ### Please RESET the board ###
Align on the write size where there is no erase size, the way Linux
does in allocate_partition(). The MTDPART_OFS_NXTBLK rounding divides
by the erase size too and takes the same alignment.
A driver which declares neither size gets an alignment of 1 and a
WARN_ON(), as a missing size must not take the boot down.
Signed-off-by: Heiko Schocher <[email protected]>
Reviewed-by: Simon Glass <[email protected]>
---
checkpatch reports two warnings and four checks on the two
printk(KERN_WARNING"mtd: partition ... force read-only\n") lines.
This patch only changes s/"erase block"/"erase/write block" in the
string of the print, so ignoring the warnings.
Changes in v3:
- The two alignment checks no longer rely on MTD_NO_ERASE being set
correctly. An alignment of zero counts as 1 with a WARN_ON(), and the
partition erase size is only taken when there is one (Simon)
- Updated the comment above the first check, which still spoke of the
erase size alone (Simon)
- Added Reviewed-by from Simon
Changes in v2:
- New patch mtd: align a partition on the write size if the device cannot erase
Testing on the board dropped for "mtd list" command:
### ERROR ### Please RESET the board ###
This is because division by erase_size, which the SPI RAM driver
sets to 0. Added for this case also sandbox test.
drivers/mtd/mtdpart.c | 44 +++++++++++++++++++++++++++++++++----------
1 file changed, 34 insertions(+), 10 deletions(-)
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index a3003cf44b0..ca13e18e353 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -563,8 +563,19 @@ static struct mtd_info *allocate_partition(struct mtd_info
*master,
const struct mtd_partition *part,
int partno, uint64_t cur_offset)
{
+ u32 wr_alignment = (master->flags & MTD_NO_ERASE) ? master->writesize :
+ master->erasesize;
struct mtd_info *slave;
+ u32 remainder;
char *name;
+ u64 tmp;
+
+ /*
+ * A master that declares neither of the two sizes leaves nothing to
+ * align to. Take every offset as aligned instead of dividing by zero.
+ */
+ if (WARN_ON(!wr_alignment))
+ wr_alignment = 1;
/* allocate the partition structure */
slave = kzalloc(sizeof(*slave), GFP_KERNEL);
@@ -665,9 +676,11 @@ static struct mtd_info *allocate_partition(struct mtd_info
*master,
slave->offset = cur_offset;
if (slave->offset == MTDPART_OFS_NXTBLK) {
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;
+ tmp = cur_offset;
+ remainder = do_div(tmp, wr_alignment);
+ if (remainder) {
+ /* Round up to the next alignment boundary */
+ slave->offset += wr_alignment - remainder;
debug("Moving partition %d: "
"0x%012llx -> 0x%012llx\n", partno,
(unsigned long long)cur_offset, (unsigned long
long)slave->offset);
@@ -731,19 +744,30 @@ static struct mtd_info *allocate_partition(struct
mtd_info *master,
slave->erasesize = master->erasesize;
}
- if ((slave->flags & MTD_WRITEABLE) &&
- mtd_mod_by_eb(slave->offset, slave)) {
- /* Doesn't start on a boundary of major erase size */
+ /*
+ * The erase size of the partition may differ from the one of the
+ * master if the master exposes several erase regions. Align to the
+ * one the partition ended up with, as long as there is one.
+ */
+ if (!(slave->flags & MTD_NO_ERASE) && slave->erasesize)
+ wr_alignment = slave->erasesize;
+
+ tmp = slave->offset;
+ remainder = do_div(tmp, wr_alignment);
+ if ((slave->flags & MTD_WRITEABLE) && remainder) {
+ /* Doesn't start on a boundary of the alignment above */
/* FIXME: Let it be writable if it is on a boundary of
* _minor_ erase size though */
slave->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->flags & MTD_WRITEABLE) &&
- mtd_mod_by_eb(slave->size, slave)) {
+
+ tmp = slave->size;
+ remainder = do_div(tmp, wr_alignment);
+ if ((slave->flags & MTD_WRITEABLE) && remainder) {
slave->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);
}
--
2.55.0