Commit ff94bc40 authored by Heiko Schocher's avatar Heiko Schocher Committed by Tom Rini
Browse files

mtd, ubi, ubifs: resync with Linux-3.14



resync ubi subsystem with linux:

commit 455c6fdbd219161bd09b1165f11699d6d73de11c
Author: Linus Torvalds <torvalds@linux-foundation.org>
Date:   Sun Mar 30 20:40:15 2014 -0700

    Linux 3.14

A nice side effect of this, is we introduce UBI Fastmap support
to U-Boot.
Signed-off-by: default avatarHeiko Schocher <hs@denx.de>
Signed-off-by: default avatarTom Rini <trini@ti.com>
Cc: Marek Vasut <marex@denx.de>
Cc: Sergey Lapin <slapin@ossfans.org>
Cc: Scott Wood <scottwood@freescale.com>
Cc: Joerg Krause <jkrause@posteo.de>
parent 0c06db59
......@@ -3338,6 +3338,9 @@ FIT uImage format:
Adds the MTD partitioning infrastructure from the Linux
kernel. Needed for UBI support.
CONFIG_MTD_NAND_VERIFY_WRITE
verify if the written data is correct reread.
- UBI support
CONFIG_CMD_UBI
......@@ -3351,6 +3354,64 @@ FIT uImage format:
Make the verbose messages from UBI stop printing. This leaves
warnings and errors enabled.
CONFIG_MTD_UBI_WL_THRESHOLD
This parameter defines the maximum difference between the highest
erase counter value and the lowest erase counter value of eraseblocks
of UBI devices. When this threshold is exceeded, UBI starts performing
wear leveling by means of moving data from eraseblock with low erase
counter to eraseblocks with high erase counter.
The default value should be OK for SLC NAND flashes, NOR flashes and
other flashes which have eraseblock life-cycle 100000 or more.
However, in case of MLC NAND flashes which typically have eraseblock
life-cycle less than 10000, the threshold should be lessened (e.g.,
to 128 or 256, although it does not have to be power of 2).
default: 4096
CONFIG_MTD_UBI_BEB_LIMIT
This option specifies the maximum bad physical eraseblocks UBI
expects on the MTD device (per 1024 eraseblocks). If the
underlying flash does not admit of bad eraseblocks (e.g. NOR
flash), this value is ignored.
NAND datasheets often specify the minimum and maximum NVM
(Number of Valid Blocks) for the flashes' endurance lifetime.
The maximum expected bad eraseblocks per 1024 eraseblocks
then can be calculated as "1024 * (1 - MinNVB / MaxNVB)",
which gives 20 for most NANDs (MaxNVB is basically the total
count of eraseblocks on the chip).
To put it differently, if this value is 20, UBI will try to
reserve about 1.9% of physical eraseblocks for bad blocks
handling. And that will be 1.9% of eraseblocks on the entire
NAND chip, not just the MTD partition UBI attaches. This means
that if you have, say, a NAND flash chip admits maximum 40 bad
eraseblocks, and it is split on two MTD partitions of the same
size, UBI will reserve 40 eraseblocks when attaching a
partition.
default: 20
CONFIG_MTD_UBI_FASTMAP
Fastmap is a mechanism which allows attaching an UBI device
in nearly constant time. Instead of scanning the whole MTD device it
only has to locate a checkpoint (called fastmap) on the device.
The on-flash fastmap contains all information needed to attach
the device. Using fastmap makes only sense on large devices where
attaching by scanning takes long. UBI will not automatically install
a fastmap on old images, but you can set the UBI parameter
CONFIG_MTD_UBI_FASTMAP_AUTOCONVERT to 1 if you want so. Please note
that fastmap-enabled images are still usable with UBI implementations
without fastmap support. On typical flash devices the whole fastmap
fits into one PEB. UBI will reserve PEBs to hold two fastmaps.
CONFIG_MTD_UBI_FASTMAP_AUTOCONVERT
Set this parameter to enable fastmap automatically on images
without a fastmap.
default: 0
- UBIFS support
CONFIG_CMD_UBIFS
......
......@@ -93,6 +93,7 @@ static void alpr_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
}
}
#if defined(CONFIG_MTD_NAND_VERIFY_WRITE)
static int alpr_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
{
int i;
......@@ -103,6 +104,7 @@ static int alpr_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len
return 0;
}
#endif
static int alpr_nand_dev_ready(struct mtd_info *mtd)
{
......@@ -128,7 +130,9 @@ int board_nand_init(struct nand_chip *nand)
nand->read_byte = alpr_nand_read_byte;
nand->write_buf = alpr_nand_write_buf;
nand->read_buf = alpr_nand_read_buf;
#if defined(CONFIG_MTD_NAND_VERIFY_WRITE)
nand->verify_buf = alpr_nand_verify_buf;
#endif
nand->dev_ready = alpr_nand_dev_ready;
return 0;
......
......@@ -18,7 +18,9 @@ static void sc_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len);
static u_char sc_nand_read_byte(struct mtd_info *mtd);
static u16 sc_nand_read_word(struct mtd_info *mtd);
static void sc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len);
#if defined(CONFIG_MTD_NAND_VERIFY_WRITE)
static int sc_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len);
#endif
static int sc_nand_device_ready(struct mtd_info *mtdinfo);
#define FPGA_NAND_CMD_MASK (0x7 << 28)
......@@ -100,6 +102,7 @@ static void sc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
}
}
#if defined(CONFIG_MTD_NAND_VERIFY_WRITE)
/**
* sc_nand_verify_buf - Verify chip data against buffer
* @mtd: MTD device structure
......@@ -116,6 +119,7 @@ static int sc_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
}
return 0;
}
#endif
/**
* sc_nand_device_ready - Check the NAND device is ready for next command.
......@@ -174,7 +178,9 @@ int board_nand_init(struct nand_chip *nand)
nand->read_word = sc_nand_read_word;
nand->write_buf = sc_nand_write_buf;
nand->read_buf = sc_nand_read_buf;
#if defined(CONFIG_MTD_NAND_VERIFY_WRITE)
nand->verify_buf = sc_nand_verify_buf;
#endif
return 0;
}
......
......@@ -188,6 +188,7 @@ static void tqm8272_write_buf(struct mtd_info *mtdinfo, const uint8_t *buf, int
*base = buf[i];
}
#if defined(CONFIG_MTD_NAND_VERIFY_WRITE)
static int tqm8272_verify_buf(struct mtd_info *mtdinfo, const uint8_t *buf, int len)
{
struct nand_chip *this = mtdinfo->priv;
......@@ -199,6 +200,7 @@ static int tqm8272_verify_buf(struct mtd_info *mtdinfo, const uint8_t *buf, int
return -1;
return 0;
}
#endif
#endif /* #ifndef CONFIG_NAND_SPL */
void board_nand_select_device(struct nand_chip *nand, int chip)
......@@ -247,7 +249,9 @@ int board_nand_init(struct nand_chip *nand)
#ifndef CONFIG_NAND_SPL
nand->write_buf = tqm8272_write_buf;
nand->read_buf = tqm8272_read_buf;
#if defined(CONFIG_MTD_NAND_VERIFY_WRITE)
nand->verify_buf = tqm8272_verify_buf;
#endif
#endif
/*
......
......@@ -19,6 +19,7 @@
#include <onenand_uboot.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/err.h>
#include <ubi_uboot.h>
#include <asm/errno.h>
#include <jffs2/load_kernel.h>
......@@ -50,33 +51,6 @@ int ubifs_is_mounted(void);
void cmd_ubifs_umount(void);
#endif
static void ubi_dump_vol_info(const struct ubi_volume *vol)
{
ubi_msg("volume information dump:");
ubi_msg("vol_id %d", vol->vol_id);
ubi_msg("reserved_pebs %d", vol->reserved_pebs);
ubi_msg("alignment %d", vol->alignment);
ubi_msg("data_pad %d", vol->data_pad);
ubi_msg("vol_type %d", vol->vol_type);
ubi_msg("name_len %d", vol->name_len);
ubi_msg("usable_leb_size %d", vol->usable_leb_size);
ubi_msg("used_ebs %d", vol->used_ebs);
ubi_msg("used_bytes %lld", vol->used_bytes);
ubi_msg("last_eb_bytes %d", vol->last_eb_bytes);
ubi_msg("corrupted %d", vol->corrupted);
ubi_msg("upd_marker %d", vol->upd_marker);
if (vol->name_len <= UBI_VOL_NAME_MAX &&
strnlen(vol->name, vol->name_len + 1) == vol->name_len) {
ubi_msg("name %s", vol->name);
} else {
ubi_msg("the 1st 5 characters of the name: %c%c%c%c%c",
vol->name[0], vol->name[1], vol->name[2],
vol->name[3], vol->name[4]);
}
printf("\n");
}
static void display_volume_info(struct ubi_device *ubi)
{
int i;
......
......@@ -38,7 +38,7 @@ static int do_ubifs_mount(cmd_tbl_t *cmdtp, int flag, int argc,
ubifs_initialized = 1;
}
ret = ubifs_mount(vol_name);
ret = uboot_ubifs_mount(vol_name);
if (ret)
return -1;
......
/*
* MTD device concatenation layer
*
* (C) 2002 Robert Kaiser <rkaiser@sysgo.de>
* Copyright © 2002 Robert Kaiser <rkaiser@sysgo.de>
* Copyright © 2002-2010 David Woodhouse <dwmw2@infradead.org>
*
* NAND support by Christian Gan <cgan@iders.ca>
*
* This code is GPL
* SPDX-License-Identifier: GPL-2.0+
*
*/
#include <linux/mtd/mtd.h>
#define __UBOOT__
#ifndef __UBOOT__
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/backing-dev.h>
#include <asm/div64.h>
#else
#include <div64.h>
#include <linux/compat.h>
#endif
#include <linux/mtd/mtd.h>
#include <linux/mtd/concat.h>
#include <ubi_uboot.h>
/*
......@@ -51,7 +67,9 @@ concat_read(struct mtd_info *mtd, loff_t from, size_t len,
int ret = 0, err;
int i;
#ifdef __UBOOT__
*retlen = 0;
#endif
for (i = 0; i < concat->num_subdev; i++) {
struct mtd_info *subdev = concat->subdev[i];
......@@ -105,7 +123,9 @@ concat_write(struct mtd_info *mtd, loff_t to, size_t len,
int err = -EINVAL;
int i;
#ifdef __UBOOT__
*retlen = 0;
#endif
for (i = 0; i < concat->num_subdev; i++) {
struct mtd_info *subdev = concat->subdev[i];
......@@ -137,6 +157,83 @@ concat_write(struct mtd_info *mtd, loff_t to, size_t len,
return err;
}
#ifndef __UBOOT__
static int
concat_writev(struct mtd_info *mtd, const struct kvec *vecs,
unsigned long count, loff_t to, size_t * retlen)
{
struct mtd_concat *concat = CONCAT(mtd);
struct kvec *vecs_copy;
unsigned long entry_low, entry_high;
size_t total_len = 0;
int i;
int err = -EINVAL;
/* Calculate total length of data */
for (i = 0; i < count; i++)
total_len += vecs[i].iov_len;
/* Check alignment */
if (mtd->writesize > 1) {
uint64_t __to = to;
if (do_div(__to, mtd->writesize) || (total_len % mtd->writesize))
return -EINVAL;
}
/* make a copy of vecs */
vecs_copy = kmemdup(vecs, sizeof(struct kvec) * count, GFP_KERNEL);
if (!vecs_copy)
return -ENOMEM;
entry_low = 0;
for (i = 0; i < concat->num_subdev; i++) {
struct mtd_info *subdev = concat->subdev[i];
size_t size, wsize, retsize, old_iov_len;
if (to >= subdev->size) {
to -= subdev->size;
continue;
}
size = min_t(uint64_t, total_len, subdev->size - to);
wsize = size; /* store for future use */
entry_high = entry_low;
while (entry_high < count) {
if (size <= vecs_copy[entry_high].iov_len)
break;
size -= vecs_copy[entry_high++].iov_len;
}
old_iov_len = vecs_copy[entry_high].iov_len;
vecs_copy[entry_high].iov_len = size;
err = mtd_writev(subdev, &vecs_copy[entry_low],
entry_high - entry_low + 1, to, &retsize);
vecs_copy[entry_high].iov_len = old_iov_len - size;
vecs_copy[entry_high].iov_base += size;
entry_low = entry_high;
if (err)
break;
*retlen += retsize;
total_len -= wsize;
if (total_len == 0)
break;
err = -EINVAL;
to = 0;
}
kfree(vecs_copy);
return err;
}
#endif
static int
concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
{
......@@ -204,7 +301,7 @@ concat_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops)
if (!(mtd->flags & MTD_WRITEABLE))
return -EROFS;
ops->retlen = 0;
ops->retlen = ops->oobretlen = 0;
for (i = 0; i < concat->num_subdev; i++) {
struct mtd_info *subdev = concat->subdev[i];
......@@ -219,7 +316,7 @@ concat_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops)
devops.len = subdev->size - to;
err = mtd_write_oob(subdev, to, &devops);
ops->retlen += devops.retlen;
ops->retlen += devops.oobretlen;
if (err)
return err;
......@@ -243,6 +340,9 @@ concat_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops)
static void concat_erase_callback(struct erase_info *instr)
{
/* Nothing to do here in U-Boot */
#ifndef __UBOOT__
wake_up((wait_queue_head_t *) instr->priv);
#endif
}
static int concat_dev_erase(struct mtd_info *mtd, struct erase_info *erase)
......@@ -316,7 +416,7 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
* to-be-erased area begins. Verify that the starting
* offset is aligned to this region's erase size:
*/
if (instr->addr & (erase_regions[i].erasesize - 1))
if (i < 0 || instr->addr & (erase_regions[i].erasesize - 1))
return -EINVAL;
/*
......@@ -329,8 +429,8 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
/*
* check if the ending offset is aligned to this region's erase size
*/
if ((instr->addr + instr->len) & (erase_regions[i].erasesize -
1))
if (i < 0 || ((instr->addr + instr->len) &
(erase_regions[i].erasesize - 1)))
return -EINVAL;
}
......@@ -422,7 +522,6 @@ static int concat_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
size = len;
err = mtd_lock(subdev, ofs, size);
if (err)
break;
......@@ -457,7 +556,6 @@ static int concat_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
size = len;
err = mtd_unlock(subdev, ofs, size);
if (err)
break;
......@@ -483,6 +581,32 @@ static void concat_sync(struct mtd_info *mtd)
}
}
#ifndef __UBOOT__
static int concat_suspend(struct mtd_info *mtd)
{
struct mtd_concat *concat = CONCAT(mtd);
int i, rc = 0;
for (i = 0; i < concat->num_subdev; i++) {
struct mtd_info *subdev = concat->subdev[i];
if ((rc = mtd_suspend(subdev)) < 0)
return rc;
}
return rc;
}
static void concat_resume(struct mtd_info *mtd)
{
struct mtd_concat *concat = CONCAT(mtd);
int i;
for (i = 0; i < concat->num_subdev; i++) {
struct mtd_info *subdev = concat->subdev[i];
mtd_resume(subdev);
}
}
#endif
static int concat_block_isbad(struct mtd_info *mtd, loff_t ofs)
{
struct mtd_concat *concat = CONCAT(mtd);
......@@ -511,9 +635,6 @@ static int concat_block_markbad(struct mtd_info *mtd, loff_t ofs)
struct mtd_concat *concat = CONCAT(mtd);
int i, err = -EINVAL;
if (!mtd_can_have_bb(concat->subdev[0]))
return 0;
for (i = 0; i < concat->num_subdev; i++) {
struct mtd_info *subdev = concat->subdev[i];
......@@ -531,6 +652,32 @@ static int concat_block_markbad(struct mtd_info *mtd, loff_t ofs)
return err;
}
/*
* try to support NOMMU mmaps on concatenated devices
* - we don't support subdev spanning as we can't guarantee it'll work
*/
static unsigned long concat_get_unmapped_area(struct mtd_info *mtd,
unsigned long len,
unsigned long offset,
unsigned long flags)
{
struct mtd_concat *concat = CONCAT(mtd);
int i;
for (i = 0; i < concat->num_subdev; i++) {
struct mtd_info *subdev = concat->subdev[i];
if (offset >= subdev->size) {
offset -= subdev->size;
continue;
}
return mtd_get_unmapped_area(subdev, len, offset, flags);
}
return (unsigned long) -ENOSYS;
}
/*
* This function constructs a virtual MTD device by concatenating
* num_devs MTD devices. A pointer to the new device object is
......@@ -539,17 +686,22 @@ static int concat_block_markbad(struct mtd_info *mtd, loff_t ofs)
*/
struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to concatenate */
int num_devs, /* number of subdevices */
#ifndef __UBOOT__
const char *name)
#else
char *name)
#endif
{ /* name for the new device */
int i;
size_t size;
struct mtd_concat *concat;
uint32_t max_erasesize, curr_erasesize;
int num_erase_region;
int max_writebufsize = 0;
debug("Concatenating MTD devices:\n");
for (i = 0; i < num_devs; i++)
debug("(%d): \"%s\"\n", i, subdev[i]->name);
printk(KERN_NOTICE "(%d): \"%s\"\n", i, subdev[i]->name);
debug("into device \"%s\"\n", name);
/* allocate the device structure */
......@@ -565,16 +717,26 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
/*
* Set up the new "super" device's MTD object structure, check for
* incompatibilites between the subdevices.
* incompatibilities between the subdevices.
*/
concat->mtd.type = subdev[0]->type;
concat->mtd.flags = subdev[0]->flags;
concat->mtd.size = subdev[0]->size;
concat->mtd.erasesize = subdev[0]->erasesize;
concat->mtd.writesize = subdev[0]->writesize;
for (i = 0; i < num_devs; i++)
if (max_writebufsize < subdev[i]->writebufsize)
max_writebufsize = subdev[i]->writebufsize;
concat->mtd.writebufsize = max_writebufsize;
concat->mtd.subpage_sft = subdev[0]->subpage_sft;
concat->mtd.oobsize = subdev[0]->oobsize;
concat->mtd.oobavail = subdev[0]->oobavail;
#ifndef __UBOOT__
if (subdev[0]->_writev)
concat->mtd._writev = concat_writev;
#endif
if (subdev[0]->_read_oob)
concat->mtd._read_oob = concat_read_oob;
if (subdev[0]->_write_oob)
......@@ -586,6 +748,10 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
concat->mtd.ecc_stats.badblocks = subdev[0]->ecc_stats.badblocks;
#ifndef __UBOOT__
concat->mtd.backing_dev_info = subdev[0]->backing_dev_info;
#endif
concat->subdev[0] = subdev[0];
for (i = 1; i < num_devs; i++) {
......@@ -613,6 +779,16 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
subdev[i]->flags & MTD_WRITEABLE;
}
#ifndef __UBOOT__
/* only permit direct mapping if the BDIs are all the same
* - copy-mapping is still permitted
*/
if (concat->mtd.backing_dev_info !=
subdev[i]->backing_dev_info)
concat->mtd.backing_dev_info =
&default_backing_dev_info;
#endif
concat->mtd.size += subdev[i]->size;
concat->mtd.ecc_stats.badblocks +=
subdev[i]->ecc_stats.badblocks;
......@@ -641,6 +817,11 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
concat->mtd._sync = concat_sync;
concat->mtd._lock = concat_lock;
concat->mtd._unlock = concat_unlock;
#ifndef __UBOOT__
concat->mtd._suspend = concat_suspend;
concat->mtd._resume = concat_resume;
#endif
concat->mtd._get_unmapped_area = concat_get_unmapped_area;
/*
* Combine the erase block size info of the subdevices:
......@@ -771,3 +952,22 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
return &concat->mtd;
}
/*
* This function destroys an MTD object obtained from concat_mtd_devs()
*/
void mtd_concat_destroy(struct mtd_info *mtd)
{
struct mtd_concat *concat = CONCAT(mtd);
if (concat->mtd.numeraseregions)
kfree(concat->mtd.eraseregions);
kfree(concat);
}
EXPORT_SYMBOL(mtd_concat_create);
EXPORT_SYMBOL(mtd_concat_destroy);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Robert Kaiser <rkaiser@sysgo.de>");
MODULE_DESCRIPTION("Generic support for concatenating of MTD devices");
This diff is collapsed.
/*
* These are exported solely for the purpose of mtd_blkdevs.c and mtdchar.c.
* You should not use them for _anything_ else.
*/