mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 10:41:38 -04:00
Merge branches 'arm', 'at91', 'bcmring', 'ep93xx', 'mach-types', 'misc' and 'w90x900' into devel
This commit is contained in:
commit
cf7a2b4fb6
1298 changed files with 53846 additions and 14528 deletions
|
|
@ -194,7 +194,7 @@ static struct mtd_partition * newpart(char *s,
|
|||
parts[this_part].name = extra_mem;
|
||||
extra_mem += name_len + 1;
|
||||
|
||||
dbg(("partition %d: name <%s>, offset %x, size %x, mask flags %x\n",
|
||||
dbg(("partition %d: name <%s>, offset %llx, size %llx, mask flags %x\n",
|
||||
this_part,
|
||||
parts[this_part].name,
|
||||
parts[this_part].offset,
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@
|
|||
#define SR_SRWD 0x80 /* SR write protect */
|
||||
|
||||
/* Define max times to check status register before we give up. */
|
||||
#define MAX_READY_WAIT_JIFFIES (10 * HZ) /* eg. M25P128 specs 6s max sector erase */
|
||||
#define MAX_READY_WAIT_JIFFIES (40 * HZ) /* M25P16 specs 40s max chip erase */
|
||||
#define CMD_SIZE 4
|
||||
|
||||
#ifdef CONFIG_M25PXX_USE_FAST_READ
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ static u16 INFTL_findfreeblock(struct INFTLrecord *inftl, int desperate)
|
|||
if (!desperate && inftl->numfreeEUNs < 2) {
|
||||
DEBUG(MTD_DEBUG_LEVEL1, "INFTL: there are too few free "
|
||||
"EUNs (%d)\n", inftl->numfreeEUNs);
|
||||
return 0xffff;
|
||||
return BLOCK_NIL;
|
||||
}
|
||||
|
||||
/* Scan for a free block */
|
||||
|
|
@ -281,7 +281,8 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
|
|||
silly = MAX_LOOPS;
|
||||
while (thisEUN < inftl->nb_blocks) {
|
||||
for (block = 0; block < inftl->EraseSize/SECTORSIZE; block ++) {
|
||||
if ((BlockMap[block] != 0xffff) || BlockDeleted[block])
|
||||
if ((BlockMap[block] != BLOCK_NIL) ||
|
||||
BlockDeleted[block])
|
||||
continue;
|
||||
|
||||
if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize)
|
||||
|
|
@ -525,7 +526,7 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block)
|
|||
if (!silly--) {
|
||||
printk(KERN_WARNING "INFTL: infinite loop in "
|
||||
"Virtual Unit Chain 0x%x\n", thisVUC);
|
||||
return 0xffff;
|
||||
return BLOCK_NIL;
|
||||
}
|
||||
|
||||
/* Skip to next block in chain */
|
||||
|
|
@ -549,7 +550,7 @@ hitused:
|
|||
* waiting to be picked up. We're going to have to fold
|
||||
* a chain to make room.
|
||||
*/
|
||||
thisEUN = INFTL_makefreeblock(inftl, 0xffff);
|
||||
thisEUN = INFTL_makefreeblock(inftl, BLOCK_NIL);
|
||||
|
||||
/*
|
||||
* Hopefully we free something, lets try again.
|
||||
|
|
@ -631,7 +632,7 @@ hitused:
|
|||
|
||||
printk(KERN_WARNING "INFTL: error folding to make room for Virtual "
|
||||
"Unit Chain 0x%x\n", thisVUC);
|
||||
return 0xffff;
|
||||
return BLOCK_NIL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -42,10 +42,8 @@
|
|||
#include <mach/hardware.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
#define SUBDEV_NAME_SIZE (BUS_ID_SIZE + 2)
|
||||
|
||||
struct armflash_subdev_info {
|
||||
char name[SUBDEV_NAME_SIZE];
|
||||
char *name;
|
||||
struct mtd_info *mtd;
|
||||
struct map_info map;
|
||||
struct flash_platform_data *plat;
|
||||
|
|
@ -134,6 +132,8 @@ static void armflash_subdev_remove(struct armflash_subdev_info *subdev)
|
|||
map_destroy(subdev->mtd);
|
||||
if (subdev->map.virt)
|
||||
iounmap(subdev->map.virt);
|
||||
kfree(subdev->name);
|
||||
subdev->name = NULL;
|
||||
release_mem_region(subdev->map.phys, subdev->map.size);
|
||||
}
|
||||
|
||||
|
|
@ -177,16 +177,22 @@ static int armflash_probe(struct platform_device *dev)
|
|||
|
||||
if (nr == 1)
|
||||
/* No MTD concatenation, just use the default name */
|
||||
snprintf(subdev->name, SUBDEV_NAME_SIZE, "%s",
|
||||
dev_name(&dev->dev));
|
||||
subdev->name = kstrdup(dev_name(&dev->dev), GFP_KERNEL);
|
||||
else
|
||||
snprintf(subdev->name, SUBDEV_NAME_SIZE, "%s-%d",
|
||||
dev_name(&dev->dev), i);
|
||||
subdev->name = kasprintf(GFP_KERNEL, "%s-%d",
|
||||
dev_name(&dev->dev), i);
|
||||
if (!subdev->name) {
|
||||
err = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
subdev->plat = plat;
|
||||
|
||||
err = armflash_subdev_probe(subdev, res);
|
||||
if (err)
|
||||
if (err) {
|
||||
kfree(subdev->name);
|
||||
subdev->name = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
info->nr_subdev = i;
|
||||
|
||||
|
|
|
|||
|
|
@ -534,7 +534,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
|
|||
&num_partitions);
|
||||
|
||||
if ((!partitions) || (num_partitions == 0)) {
|
||||
printk(KERN_ERR "atmel_nand: No parititions defined, or unsupported device.\n");
|
||||
printk(KERN_ERR "atmel_nand: No partitions defined, or unsupported device.\n");
|
||||
res = ENXIO;
|
||||
goto err_no_partitions;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/nand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
|
|
@ -541,7 +543,7 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
|
|||
struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
|
||||
mtd);
|
||||
unsigned long timeo = jiffies;
|
||||
int status, state = this->state;
|
||||
int status = NAND_STATUS_FAIL, state = this->state;
|
||||
|
||||
if (state == FL_ERASING)
|
||||
timeo += (HZ * 400) / 1000;
|
||||
|
|
@ -556,8 +558,9 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
|
|||
|
||||
while (time_before(jiffies, timeo)) {
|
||||
status = __raw_readb(this->IO_ADDR_R);
|
||||
if (!(status & 0x40))
|
||||
if (status & NAND_STATUS_READY)
|
||||
break;
|
||||
cond_resched();
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,8 +24,11 @@
|
|||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/nand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/ts72xx.h>
|
||||
|
||||
#include <asm/sizes.h>
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -208,7 +208,7 @@ static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate )
|
|||
/* Normally, we force a fold to happen before we run out of free blocks completely */
|
||||
if (!desperate && nftl->numfreeEUNs < 2) {
|
||||
DEBUG(MTD_DEBUG_LEVEL1, "NFTL_findfreeblock: there are too few free EUNs\n");
|
||||
return 0xffff;
|
||||
return BLOCK_NIL;
|
||||
}
|
||||
|
||||
/* Scan for a free block */
|
||||
|
|
@ -230,11 +230,11 @@ static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate )
|
|||
printk("Argh! No free blocks found! LastFreeEUN = %d, "
|
||||
"FirstEUN = %d\n", nftl->LastFreeEUN,
|
||||
le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN));
|
||||
return 0xffff;
|
||||
return BLOCK_NIL;
|
||||
}
|
||||
} while (pot != nftl->LastFreeEUN);
|
||||
|
||||
return 0xffff;
|
||||
return BLOCK_NIL;
|
||||
}
|
||||
|
||||
static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned pendingblock )
|
||||
|
|
@ -431,7 +431,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
|
|||
|
||||
/* add the header so that it is now a valid chain */
|
||||
oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);
|
||||
oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff;
|
||||
oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = BLOCK_NIL;
|
||||
|
||||
nftl_write_oob(mtd, (nftl->EraseSize * targetEUN) + 8,
|
||||
8, &retlen, (char *)&oob.u);
|
||||
|
|
@ -515,7 +515,7 @@ static u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock)
|
|||
if (ChainLength < 2) {
|
||||
printk(KERN_WARNING "No Virtual Unit Chains available for folding. "
|
||||
"Failing request\n");
|
||||
return 0xffff;
|
||||
return BLOCK_NIL;
|
||||
}
|
||||
|
||||
return NFTL_foldchain (nftl, LongestChain, pendingblock);
|
||||
|
|
@ -578,7 +578,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
|
|||
printk(KERN_WARNING
|
||||
"Infinite loop in Virtual Unit Chain 0x%x\n",
|
||||
thisVUC);
|
||||
return 0xffff;
|
||||
return BLOCK_NIL;
|
||||
}
|
||||
|
||||
/* Skip to next block in chain */
|
||||
|
|
@ -601,7 +601,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
|
|||
//u16 startEUN = nftl->EUNtable[thisVUC];
|
||||
|
||||
//printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC);
|
||||
writeEUN = NFTL_makefreeblock(nftl, 0xffff);
|
||||
writeEUN = NFTL_makefreeblock(nftl, BLOCK_NIL);
|
||||
|
||||
if (writeEUN == BLOCK_NIL) {
|
||||
/* OK, we accept that the above comment is
|
||||
|
|
@ -673,7 +673,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
|
|||
|
||||
printk(KERN_WARNING "Error folding to make room for Virtual Unit Chain 0x%x\n",
|
||||
thisVUC);
|
||||
return 0xffff;
|
||||
return BLOCK_NIL;
|
||||
}
|
||||
|
||||
static int nftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
|
||||
|
|
|
|||
|
|
@ -657,6 +657,11 @@ static int io_init(struct ubi_device *ubi)
|
|||
if (ubi->mtd->block_isbad && ubi->mtd->block_markbad)
|
||||
ubi->bad_allowed = 1;
|
||||
|
||||
if (ubi->mtd->type == MTD_NORFLASH) {
|
||||
ubi_assert(ubi->mtd->writesize == 1);
|
||||
ubi->nor_flash = 1;
|
||||
}
|
||||
|
||||
ubi->min_io_size = ubi->mtd->writesize;
|
||||
ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft;
|
||||
|
||||
|
|
@ -996,6 +1001,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
|
|||
ubi_msg("number of PEBs reserved for bad PEB handling: %d",
|
||||
ubi->beb_rsvd_pebs);
|
||||
ubi_msg("max/mean erase counter: %d/%d", ubi->max_ec, ubi->mean_ec);
|
||||
ubi_msg("image sequence number: %d", ubi->image_seq);
|
||||
|
||||
/*
|
||||
* The below lock makes sure we do not race with 'ubi_thread()' which
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
|
|||
be32_to_cpu(ec_hdr->vid_hdr_offset));
|
||||
printk(KERN_DEBUG "\tdata_offset %d\n",
|
||||
be32_to_cpu(ec_hdr->data_offset));
|
||||
printk(KERN_DEBUG "\timage_seq %d\n",
|
||||
be32_to_cpu(ec_hdr->image_seq));
|
||||
printk(KERN_DEBUG "\thdr_crc %#08x\n",
|
||||
be32_to_cpu(ec_hdr->hdr_crc));
|
||||
printk(KERN_DEBUG "erase counter header hexdump:\n");
|
||||
|
|
|
|||
|
|
@ -93,6 +93,12 @@ void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req);
|
|||
#define UBI_IO_DEBUG 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
|
||||
int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len);
|
||||
#else
|
||||
#define ubi_dbg_check_all_ff(ubi, pnum, offset, len) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG_DISABLE_BGT
|
||||
#define DBG_DISABLE_BGT 1
|
||||
#else
|
||||
|
|
@ -167,6 +173,7 @@ static inline int ubi_dbg_is_erase_failure(void)
|
|||
#define ubi_dbg_is_bitflip() 0
|
||||
#define ubi_dbg_is_write_failure() 0
|
||||
#define ubi_dbg_is_erase_failure() 0
|
||||
#define ubi_dbg_check_all_ff(ubi, pnum, offset, len) 0
|
||||
|
||||
#endif /* !CONFIG_MTD_UBI_DEBUG */
|
||||
#endif /* !__UBI_DEBUG_H__ */
|
||||
|
|
|
|||
|
|
@ -98,17 +98,12 @@ static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
|
|||
static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum);
|
||||
static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum,
|
||||
const struct ubi_vid_hdr *vid_hdr);
|
||||
static int paranoid_check_all_ff(struct ubi_device *ubi, int pnum, int offset,
|
||||
int len);
|
||||
static int paranoid_check_empty(struct ubi_device *ubi, int pnum);
|
||||
#else
|
||||
#define paranoid_check_not_bad(ubi, pnum) 0
|
||||
#define paranoid_check_peb_ec_hdr(ubi, pnum) 0
|
||||
#define paranoid_check_ec_hdr(ubi, pnum, ec_hdr) 0
|
||||
#define paranoid_check_peb_vid_hdr(ubi, pnum) 0
|
||||
#define paranoid_check_vid_hdr(ubi, pnum, vid_hdr) 0
|
||||
#define paranoid_check_all_ff(ubi, pnum, offset, len) 0
|
||||
#define paranoid_check_empty(ubi, pnum) 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
|
@ -244,7 +239,7 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
|
|||
return err > 0 ? -EINVAL : err;
|
||||
|
||||
/* The area we are writing to has to contain all 0xFF bytes */
|
||||
err = paranoid_check_all_ff(ubi, pnum, offset, len);
|
||||
err = ubi_dbg_check_all_ff(ubi, pnum, offset, len);
|
||||
if (err)
|
||||
return err > 0 ? -EINVAL : err;
|
||||
|
||||
|
|
@ -271,8 +266,8 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
|
|||
addr = (loff_t)pnum * ubi->peb_size + offset;
|
||||
err = ubi->mtd->write(ubi->mtd, addr, len, &written, buf);
|
||||
if (err) {
|
||||
ubi_err("error %d while writing %d bytes to PEB %d:%d, written"
|
||||
" %zd bytes", err, len, pnum, offset, written);
|
||||
ubi_err("error %d while writing %d bytes to PEB %d:%d, written "
|
||||
"%zd bytes", err, len, pnum, offset, written);
|
||||
ubi_dbg_dump_stack();
|
||||
} else
|
||||
ubi_assert(written == len);
|
||||
|
|
@ -350,7 +345,7 @@ retry:
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
err = paranoid_check_all_ff(ubi, pnum, 0, ubi->peb_size);
|
||||
err = ubi_dbg_check_all_ff(ubi, pnum, 0, ubi->peb_size);
|
||||
if (err)
|
||||
return err > 0 ? -EINVAL : err;
|
||||
|
||||
|
|
@ -458,6 +453,54 @@ out:
|
|||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* nor_erase_prepare - prepare a NOR flash PEB for erasure.
|
||||
* @ubi: UBI device description object
|
||||
* @pnum: physical eraseblock number to prepare
|
||||
*
|
||||
* NOR flash, or at least some of them, have peculiar embedded PEB erasure
|
||||
* algorithm: the PEB is first filled with zeroes, then it is erased. And
|
||||
* filling with zeroes starts from the end of the PEB. This was observed with
|
||||
* Spansion S29GL512N NOR flash.
|
||||
*
|
||||
* This means that in case of a power cut we may end up with intact data at the
|
||||
* beginning of the PEB, and all zeroes at the end of PEB. In other words, the
|
||||
* EC and VID headers are OK, but a large chunk of data at the end of PEB is
|
||||
* zeroed. This makes UBI mistakenly treat this PEB as used and associate it
|
||||
* with an LEB, which leads to subsequent failures (e.g., UBIFS fails).
|
||||
*
|
||||
* This function is called before erasing NOR PEBs and it zeroes out EC and VID
|
||||
* magic numbers in order to invalidate them and prevent the failures. Returns
|
||||
* zero in case of success and a negative error code in case of failure.
|
||||
*/
|
||||
static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
|
||||
{
|
||||
int err;
|
||||
size_t written;
|
||||
loff_t addr;
|
||||
uint32_t data = 0;
|
||||
|
||||
addr = (loff_t)pnum * ubi->peb_size;
|
||||
err = ubi->mtd->write(ubi->mtd, addr, 4, &written, (void *)&data);
|
||||
if (err) {
|
||||
ubi_err("error %d while writing 4 bytes to PEB %d:%d, written "
|
||||
"%zd bytes", err, pnum, 0, written);
|
||||
ubi_dbg_dump_stack();
|
||||
return err;
|
||||
}
|
||||
|
||||
addr += ubi->vid_hdr_aloffset;
|
||||
err = ubi->mtd->write(ubi->mtd, addr, 4, &written, (void *)&data);
|
||||
if (err) {
|
||||
ubi_err("error %d while writing 4 bytes to PEB %d:%d, written "
|
||||
"%zd bytes", err, pnum, ubi->vid_hdr_aloffset, written);
|
||||
ubi_dbg_dump_stack();
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ubi_io_sync_erase - synchronously erase a physical eraseblock.
|
||||
* @ubi: UBI device description object
|
||||
|
|
@ -489,6 +532,12 @@ int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture)
|
|||
return -EROFS;
|
||||
}
|
||||
|
||||
if (ubi->nor_flash) {
|
||||
err = nor_erase_prepare(ubi, pnum);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (torture) {
|
||||
ret = torture_peb(ubi, pnum);
|
||||
if (ret < 0)
|
||||
|
|
@ -672,11 +721,6 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
|
|||
if (read_err != -EBADMSG &&
|
||||
check_pattern(ec_hdr, 0xFF, UBI_EC_HDR_SIZE)) {
|
||||
/* The physical eraseblock is supposedly empty */
|
||||
err = paranoid_check_all_ff(ubi, pnum, 0,
|
||||
ubi->peb_size);
|
||||
if (err)
|
||||
return err > 0 ? UBI_IO_BAD_EC_HDR : err;
|
||||
|
||||
if (verbose)
|
||||
ubi_warn("no EC header found at PEB %d, "
|
||||
"only 0xFF bytes", pnum);
|
||||
|
|
@ -752,6 +796,7 @@ int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum,
|
|||
ec_hdr->version = UBI_VERSION;
|
||||
ec_hdr->vid_hdr_offset = cpu_to_be32(ubi->vid_hdr_offset);
|
||||
ec_hdr->data_offset = cpu_to_be32(ubi->leb_start);
|
||||
ec_hdr->image_seq = cpu_to_be32(ubi->image_seq);
|
||||
crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
|
||||
ec_hdr->hdr_crc = cpu_to_be32(crc);
|
||||
|
||||
|
|
@ -947,15 +992,6 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
|
|||
if (read_err != -EBADMSG &&
|
||||
check_pattern(vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) {
|
||||
/* The physical eraseblock is supposedly free */
|
||||
|
||||
/*
|
||||
* The below is just a paranoid check, it has to be
|
||||
* compiled out if paranoid checks are disabled.
|
||||
*/
|
||||
err = paranoid_check_empty(ubi, pnum);
|
||||
if (err)
|
||||
return err > 0 ? UBI_IO_BAD_VID_HDR : err;
|
||||
|
||||
if (verbose)
|
||||
ubi_warn("no VID header found at PEB %d, "
|
||||
"only 0xFF bytes", pnum);
|
||||
|
|
@ -1229,7 +1265,7 @@ exit:
|
|||
}
|
||||
|
||||
/**
|
||||
* paranoid_check_all_ff - check that a region of flash is empty.
|
||||
* ubi_dbg_check_all_ff - check that a region of flash is empty.
|
||||
* @ubi: UBI device description object
|
||||
* @pnum: the physical eraseblock number to check
|
||||
* @offset: the starting offset within the physical eraseblock to check
|
||||
|
|
@ -1239,8 +1275,7 @@ exit:
|
|||
* @offset of the physical eraseblock @pnum, %1 if not, and a negative error
|
||||
* code if an error occurred.
|
||||
*/
|
||||
static int paranoid_check_all_ff(struct ubi_device *ubi, int pnum, int offset,
|
||||
int len)
|
||||
int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len)
|
||||
{
|
||||
size_t read;
|
||||
int err;
|
||||
|
|
@ -1276,74 +1311,4 @@ error:
|
|||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* paranoid_check_empty - whether a PEB is empty.
|
||||
* @ubi: UBI device description object
|
||||
* @pnum: the physical eraseblock number to check
|
||||
*
|
||||
* This function makes sure PEB @pnum is empty, which means it contains only
|
||||
* %0xFF data bytes. Returns zero if the PEB is empty, %1 if not, and a
|
||||
* negative error code in case of failure.
|
||||
*
|
||||
* Empty PEBs have the EC header, and do not have the VID header. The caller of
|
||||
* this function should have already made sure the PEB does not have the VID
|
||||
* header. However, this function re-checks that, because it is possible that
|
||||
* the header and data has already been written to the PEB.
|
||||
*
|
||||
* Let's consider a possible scenario. Suppose there are 2 tasks - A and B.
|
||||
* Task A is in 'wear_leveling_worker()'. It is reading VID header of PEB X to
|
||||
* find which LEB it corresponds to. PEB X is currently unmapped, and has no
|
||||
* VID header. Task B is trying to write to PEB X.
|
||||
*
|
||||
* Task A: in 'ubi_io_read_vid_hdr()': reads the VID header from PEB X. The
|
||||
* read data contain all 0xFF bytes;
|
||||
* Task B: writes VID header and some data to PEB X;
|
||||
* Task A: assumes PEB X is empty, calls 'paranoid_check_empty()'. And if we
|
||||
* do not re-read the VID header, and do not cancel the checking if it
|
||||
* is there, we fail.
|
||||
*/
|
||||
static int paranoid_check_empty(struct ubi_device *ubi, int pnum)
|
||||
{
|
||||
int err, offs = ubi->vid_hdr_aloffset, len = ubi->vid_hdr_alsize;
|
||||
size_t read;
|
||||
uint32_t magic;
|
||||
const struct ubi_vid_hdr *vid_hdr;
|
||||
|
||||
mutex_lock(&ubi->dbg_buf_mutex);
|
||||
err = ubi->mtd->read(ubi->mtd, offs, len, &read, ubi->dbg_peb_buf);
|
||||
if (err && err != -EUCLEAN) {
|
||||
ubi_err("error %d while reading %d bytes from PEB %d:%d, "
|
||||
"read %zd bytes", err, len, pnum, offs, read);
|
||||
goto error;
|
||||
}
|
||||
|
||||
vid_hdr = ubi->dbg_peb_buf;
|
||||
magic = be32_to_cpu(vid_hdr->magic);
|
||||
if (magic == UBI_VID_HDR_MAGIC)
|
||||
/* The PEB contains VID header, so it is not empty */
|
||||
goto out;
|
||||
|
||||
err = check_pattern(ubi->dbg_peb_buf, 0xFF, len);
|
||||
if (err == 0) {
|
||||
ubi_err("flash region at PEB %d:%d, length %d does not "
|
||||
"contain all 0xFF bytes", pnum, offs, len);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&ubi->dbg_buf_mutex);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
ubi_err("paranoid check failed for PEB %d", pnum);
|
||||
ubi_msg("hex dump of the %d-%d region", offs, offs + len);
|
||||
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
|
||||
ubi->dbg_peb_buf, len, 1);
|
||||
err = 1;
|
||||
error:
|
||||
ubi_dbg_dump_stack();
|
||||
mutex_unlock(&ubi->dbg_buf_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */
|
||||
|
|
|
|||
|
|
@ -757,6 +757,8 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
|
|||
si->is_empty = 0;
|
||||
|
||||
if (!ec_corr) {
|
||||
int image_seq;
|
||||
|
||||
/* Make sure UBI version is OK */
|
||||
if (ech->version != UBI_VERSION) {
|
||||
ubi_err("this UBI version is %d, image version is %d",
|
||||
|
|
@ -778,6 +780,18 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
|
|||
ubi_dbg_dump_ec_hdr(ech);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
image_seq = be32_to_cpu(ech->ec);
|
||||
if (!si->image_seq_set) {
|
||||
ubi->image_seq = image_seq;
|
||||
si->image_seq_set = 1;
|
||||
} else if (ubi->image_seq != image_seq) {
|
||||
ubi_err("bad image sequence number %d in PEB %d, "
|
||||
"expected %d", image_seq, pnum, ubi->image_seq);
|
||||
ubi_dbg_dump_ec_hdr(ech);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* OK, we've done with the EC header, let's look at the VID header */
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ struct ubi_scan_volume {
|
|||
* @mean_ec: mean erase counter value
|
||||
* @ec_sum: a temporary variable used when calculating @mean_ec
|
||||
* @ec_count: a temporary variable used when calculating @mean_ec
|
||||
* @image_seq_set: indicates @ubi->image_seq is known
|
||||
*
|
||||
* This data structure contains the result of scanning and may be used by other
|
||||
* UBI sub-systems to build final UBI data structures, further error-recovery
|
||||
|
|
@ -124,6 +125,7 @@ struct ubi_scan_info {
|
|||
int mean_ec;
|
||||
uint64_t ec_sum;
|
||||
int ec_count;
|
||||
int image_seq_set;
|
||||
};
|
||||
|
||||
struct ubi_device;
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ enum {
|
|||
* @ec: the erase counter
|
||||
* @vid_hdr_offset: where the VID header starts
|
||||
* @data_offset: where the user data start
|
||||
* @image_seq: image sequence number
|
||||
* @padding2: reserved for future, zeroes
|
||||
* @hdr_crc: erase counter header CRC checksum
|
||||
*
|
||||
|
|
@ -144,6 +145,14 @@ enum {
|
|||
* volume identifier header and user data, relative to the beginning of the
|
||||
* physical eraseblock. These values have to be the same for all physical
|
||||
* eraseblocks.
|
||||
*
|
||||
* The @image_seq field is used to validate a UBI image that has been prepared
|
||||
* for a UBI device. The @image_seq value can be any value, but it must be the
|
||||
* same on all eraseblocks. UBI will ensure that all new erase counter headers
|
||||
* also contain this value, and will check the value when scanning at start-up.
|
||||
* One way to make use of @image_seq is to increase its value by one every time
|
||||
* an image is flashed over an existing image, then, if the flashing does not
|
||||
* complete, UBI will detect the error when scanning.
|
||||
*/
|
||||
struct ubi_ec_hdr {
|
||||
__be32 magic;
|
||||
|
|
@ -152,7 +161,8 @@ struct ubi_ec_hdr {
|
|||
__be64 ec; /* Warning: the current limit is 31-bit anyway! */
|
||||
__be32 vid_hdr_offset;
|
||||
__be32 data_offset;
|
||||
__u8 padding2[36];
|
||||
__be32 image_seq;
|
||||
__u8 padding2[32];
|
||||
__be32 hdr_crc;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
|
|
|||
|
|
@ -301,6 +301,7 @@ struct ubi_wl_entry;
|
|||
* @vol->readers, @vol->writers, @vol->exclusive,
|
||||
* @vol->ref_count, @vol->mapping and @vol->eba_tbl.
|
||||
* @ref_count: count of references on the UBI device
|
||||
* @image_seq: image sequence number recorded on EC headers
|
||||
*
|
||||
* @rsvd_pebs: count of reserved physical eraseblocks
|
||||
* @avail_pebs: count of available physical eraseblocks
|
||||
|
|
@ -372,6 +373,7 @@ struct ubi_wl_entry;
|
|||
* @vid_hdr_shift: contains @vid_hdr_offset - @vid_hdr_aloffset
|
||||
* @bad_allowed: whether the MTD device admits of bad physical eraseblocks or
|
||||
* not
|
||||
* @nor_flash: non-zero if working on top of NOR flash
|
||||
* @mtd: MTD device descriptor
|
||||
*
|
||||
* @peb_buf1: a buffer of PEB size used for different purposes
|
||||
|
|
@ -390,6 +392,7 @@ struct ubi_device {
|
|||
struct ubi_volume *volumes[UBI_MAX_VOLUMES+UBI_INT_VOL_COUNT];
|
||||
spinlock_t volumes_lock;
|
||||
int ref_count;
|
||||
int image_seq;
|
||||
|
||||
int rsvd_pebs;
|
||||
int avail_pebs;
|
||||
|
|
@ -452,7 +455,8 @@ struct ubi_device {
|
|||
int vid_hdr_offset;
|
||||
int vid_hdr_aloffset;
|
||||
int vid_hdr_shift;
|
||||
int bad_allowed;
|
||||
unsigned int bad_allowed:1;
|
||||
unsigned int nor_flash:1;
|
||||
struct mtd_info *mtd;
|
||||
|
||||
void *peb_buf1;
|
||||
|
|
|
|||
|
|
@ -459,6 +459,14 @@ retry:
|
|||
dbg_wl("PEB %d EC %d", e->pnum, e->ec);
|
||||
prot_queue_add(ubi, e);
|
||||
spin_unlock(&ubi->wl_lock);
|
||||
|
||||
err = ubi_dbg_check_all_ff(ubi, e->pnum, ubi->vid_hdr_aloffset,
|
||||
ubi->peb_size - ubi->vid_hdr_aloffset);
|
||||
if (err) {
|
||||
ubi_err("new PEB %d does not contain all 0xFF bytes", e->pnum);
|
||||
return err > 0 ? -EINVAL : err;
|
||||
}
|
||||
|
||||
return e->pnum;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue