mirror of
https://github.com/Fishwaldo/u-boot.git
synced 2025-03-18 21:21:37 +00:00
Merge branch 'master' of git://git.denx.de/u-boot-nand-flash
This commit is contained in:
commit
bff4fae4fc
9 changed files with 129 additions and 63 deletions
|
@ -93,13 +93,13 @@
|
||||||
DECLARE_GLOBAL_DATA_PTR;
|
DECLARE_GLOBAL_DATA_PTR;
|
||||||
|
|
||||||
/* special size referring to all the remaining space in a partition */
|
/* special size referring to all the remaining space in a partition */
|
||||||
#define SIZE_REMAINING 0xFFFFFFFF
|
#define SIZE_REMAINING (~0llu)
|
||||||
|
|
||||||
/* special offset value, it is used when not provided by user
|
/* special offset value, it is used when not provided by user
|
||||||
*
|
*
|
||||||
* this value is used temporarily during parsing, later such offests
|
* this value is used temporarily during parsing, later such offests
|
||||||
* are recalculated */
|
* are recalculated */
|
||||||
#define OFFSET_NOT_SPECIFIED 0xFFFFFFFF
|
#define OFFSET_NOT_SPECIFIED (~0llu)
|
||||||
|
|
||||||
/* minimum partition size */
|
/* minimum partition size */
|
||||||
#define MIN_PART_SIZE 4096
|
#define MIN_PART_SIZE 4096
|
||||||
|
@ -160,9 +160,9 @@ static int device_del(struct mtd_device *dev);
|
||||||
* @param retptr output pointer to next char after parse completes (output)
|
* @param retptr output pointer to next char after parse completes (output)
|
||||||
* @return resulting unsigned int
|
* @return resulting unsigned int
|
||||||
*/
|
*/
|
||||||
static unsigned long memsize_parse (const char *const ptr, const char **retptr)
|
static u64 memsize_parse (const char *const ptr, const char **retptr)
|
||||||
{
|
{
|
||||||
unsigned long ret = simple_strtoul(ptr, (char **)retptr, 0);
|
u64 ret = simple_strtoull(ptr, (char **)retptr, 0);
|
||||||
|
|
||||||
switch (**retptr) {
|
switch (**retptr) {
|
||||||
case 'G':
|
case 'G':
|
||||||
|
@ -193,20 +193,20 @@ static unsigned long memsize_parse (const char *const ptr, const char **retptr)
|
||||||
* @param buf output buffer
|
* @param buf output buffer
|
||||||
* @param size size to be converted to string
|
* @param size size to be converted to string
|
||||||
*/
|
*/
|
||||||
static void memsize_format(char *buf, u32 size)
|
static void memsize_format(char *buf, u64 size)
|
||||||
{
|
{
|
||||||
#define SIZE_GB ((u32)1024*1024*1024)
|
#define SIZE_GB ((u32)1024*1024*1024)
|
||||||
#define SIZE_MB ((u32)1024*1024)
|
#define SIZE_MB ((u32)1024*1024)
|
||||||
#define SIZE_KB ((u32)1024)
|
#define SIZE_KB ((u32)1024)
|
||||||
|
|
||||||
if ((size % SIZE_GB) == 0)
|
if ((size % SIZE_GB) == 0)
|
||||||
sprintf(buf, "%ug", size/SIZE_GB);
|
sprintf(buf, "%llug", size/SIZE_GB);
|
||||||
else if ((size % SIZE_MB) == 0)
|
else if ((size % SIZE_MB) == 0)
|
||||||
sprintf(buf, "%um", size/SIZE_MB);
|
sprintf(buf, "%llum", size/SIZE_MB);
|
||||||
else if (size % SIZE_KB == 0)
|
else if (size % SIZE_KB == 0)
|
||||||
sprintf(buf, "%uk", size/SIZE_KB);
|
sprintf(buf, "%lluk", size/SIZE_KB);
|
||||||
else
|
else
|
||||||
sprintf(buf, "%u", size);
|
sprintf(buf, "%llu", size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -310,6 +310,7 @@ static int part_validate_eraseblock(struct mtdids *id, struct part_info *part)
|
||||||
struct mtd_info *mtd = NULL;
|
struct mtd_info *mtd = NULL;
|
||||||
int i, j;
|
int i, j;
|
||||||
ulong start;
|
ulong start;
|
||||||
|
u64 offset, size;
|
||||||
|
|
||||||
if (get_mtd_info(id->type, id->num, &mtd))
|
if (get_mtd_info(id->type, id->num, &mtd))
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -321,14 +322,16 @@ static int part_validate_eraseblock(struct mtdids *id, struct part_info *part)
|
||||||
* Only one eraseregion (NAND, OneNAND or uniform NOR),
|
* Only one eraseregion (NAND, OneNAND or uniform NOR),
|
||||||
* checking for alignment is easy here
|
* checking for alignment is easy here
|
||||||
*/
|
*/
|
||||||
if ((unsigned long)part->offset % mtd->erasesize) {
|
offset = part->offset;
|
||||||
|
if (do_div(offset, mtd->erasesize)) {
|
||||||
printf("%s%d: partition (%s) start offset"
|
printf("%s%d: partition (%s) start offset"
|
||||||
"alignment incorrect\n",
|
"alignment incorrect\n",
|
||||||
MTD_DEV_TYPE(id->type), id->num, part->name);
|
MTD_DEV_TYPE(id->type), id->num, part->name);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (part->size % mtd->erasesize) {
|
size = part->size;
|
||||||
|
if (do_div(size, mtd->erasesize)) {
|
||||||
printf("%s%d: partition (%s) size alignment incorrect\n",
|
printf("%s%d: partition (%s) size alignment incorrect\n",
|
||||||
MTD_DEV_TYPE(id->type), id->num, part->name);
|
MTD_DEV_TYPE(id->type), id->num, part->name);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -395,7 +398,7 @@ static int part_validate(struct mtdids *id, struct part_info *part)
|
||||||
part->size = id->size - part->offset;
|
part->size = id->size - part->offset;
|
||||||
|
|
||||||
if (part->offset > id->size) {
|
if (part->offset > id->size) {
|
||||||
printf("%s: offset %08x beyond flash size %08x\n",
|
printf("%s: offset %08llx beyond flash size %08llx\n",
|
||||||
id->mtd_id, part->offset, id->size);
|
id->mtd_id, part->offset, id->size);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -578,8 +581,8 @@ static int part_add(struct mtd_device *dev, struct part_info *part)
|
||||||
static int part_parse(const char *const partdef, const char **ret, struct part_info **retpart)
|
static int part_parse(const char *const partdef, const char **ret, struct part_info **retpart)
|
||||||
{
|
{
|
||||||
struct part_info *part;
|
struct part_info *part;
|
||||||
unsigned long size;
|
u64 size;
|
||||||
unsigned long offset;
|
u64 offset;
|
||||||
const char *name;
|
const char *name;
|
||||||
int name_len;
|
int name_len;
|
||||||
unsigned int mask_flags;
|
unsigned int mask_flags;
|
||||||
|
@ -598,7 +601,7 @@ static int part_parse(const char *const partdef, const char **ret, struct part_i
|
||||||
} else {
|
} else {
|
||||||
size = memsize_parse(p, &p);
|
size = memsize_parse(p, &p);
|
||||||
if (size < MIN_PART_SIZE) {
|
if (size < MIN_PART_SIZE) {
|
||||||
printf("partition size too small (%lx)\n", size);
|
printf("partition size too small (%llx)\n", size);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -670,14 +673,14 @@ static int part_parse(const char *const partdef, const char **ret, struct part_i
|
||||||
part->auto_name = 0;
|
part->auto_name = 0;
|
||||||
} else {
|
} else {
|
||||||
/* auto generated name in form of size@offset */
|
/* auto generated name in form of size@offset */
|
||||||
sprintf(part->name, "0x%08lx@0x%08lx", size, offset);
|
sprintf(part->name, "0x%08llx@0x%08llx", size, offset);
|
||||||
part->auto_name = 1;
|
part->auto_name = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
part->name[name_len - 1] = '\0';
|
part->name[name_len - 1] = '\0';
|
||||||
INIT_LIST_HEAD(&part->link);
|
INIT_LIST_HEAD(&part->link);
|
||||||
|
|
||||||
debug("+ partition: name %-22s size 0x%08x offset 0x%08x mask flags %d\n",
|
debug("+ partition: name %-22s size 0x%08llx offset 0x%08llx mask flags %d\n",
|
||||||
part->name, part->size,
|
part->name, part->size,
|
||||||
part->offset, part->mask_flags);
|
part->offset, part->mask_flags);
|
||||||
|
|
||||||
|
@ -693,7 +696,7 @@ static int part_parse(const char *const partdef, const char **ret, struct part_i
|
||||||
* @param size a pointer to the size of the mtd device (output)
|
* @param size a pointer to the size of the mtd device (output)
|
||||||
* @return 0 if device is valid, 1 otherwise
|
* @return 0 if device is valid, 1 otherwise
|
||||||
*/
|
*/
|
||||||
static int mtd_device_validate(u8 type, u8 num, u32 *size)
|
static int mtd_device_validate(u8 type, u8 num, u64 *size)
|
||||||
{
|
{
|
||||||
struct mtd_info *mtd = NULL;
|
struct mtd_info *mtd = NULL;
|
||||||
|
|
||||||
|
@ -826,7 +829,7 @@ static int device_parse(const char *const mtd_dev, const char **ret, struct mtd_
|
||||||
LIST_HEAD(tmp_list);
|
LIST_HEAD(tmp_list);
|
||||||
struct list_head *entry, *n;
|
struct list_head *entry, *n;
|
||||||
u16 num_parts;
|
u16 num_parts;
|
||||||
u32 offset;
|
u64 offset;
|
||||||
int err = 1;
|
int err = 1;
|
||||||
|
|
||||||
debug("===device_parse===\n");
|
debug("===device_parse===\n");
|
||||||
|
@ -1071,7 +1074,8 @@ static int generate_mtdparts(char *buf, u32 buflen)
|
||||||
struct part_info *part, *prev_part;
|
struct part_info *part, *prev_part;
|
||||||
char *p = buf;
|
char *p = buf;
|
||||||
char tmpbuf[32];
|
char tmpbuf[32];
|
||||||
u32 size, offset, len, part_cnt;
|
u64 size, offset;
|
||||||
|
u32 len, part_cnt;
|
||||||
u32 maxlen = buflen - 1;
|
u32 maxlen = buflen - 1;
|
||||||
|
|
||||||
debug("--- generate_mtdparts ---\n");
|
debug("--- generate_mtdparts ---\n");
|
||||||
|
@ -1270,7 +1274,7 @@ static void print_partition_table(void)
|
||||||
|
|
||||||
list_for_each(pentry, &dev->parts) {
|
list_for_each(pentry, &dev->parts) {
|
||||||
part = list_entry(pentry, struct part_info, link);
|
part = list_entry(pentry, struct part_info, link);
|
||||||
printf("%2d: %-20s0x%08x\t0x%08x\t%d\n",
|
printf("%2d: %-20s0x%08llx\t0x%08llx\t%d\n",
|
||||||
part_num, part->name, part->size,
|
part_num, part->name, part->size,
|
||||||
part->offset, part->mask_flags);
|
part->offset, part->mask_flags);
|
||||||
#endif /* defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) */
|
#endif /* defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) */
|
||||||
|
@ -1297,7 +1301,7 @@ static void list_partitions(void)
|
||||||
if (current_mtd_dev) {
|
if (current_mtd_dev) {
|
||||||
part = mtd_part_info(current_mtd_dev, current_mtd_partnum);
|
part = mtd_part_info(current_mtd_dev, current_mtd_partnum);
|
||||||
if (part) {
|
if (part) {
|
||||||
printf("\nactive partition: %s%d,%d - (%s) 0x%08x @ 0x%08x\n",
|
printf("\nactive partition: %s%d,%d - (%s) 0x%08llx @ 0x%08llx\n",
|
||||||
MTD_DEV_TYPE(current_mtd_dev->id->type),
|
MTD_DEV_TYPE(current_mtd_dev->id->type),
|
||||||
current_mtd_dev->id->num, current_mtd_partnum,
|
current_mtd_dev->id->num, current_mtd_partnum,
|
||||||
part->name, part->size, part->offset);
|
part->name, part->size, part->offset);
|
||||||
|
@ -1397,7 +1401,7 @@ static int delete_partition(const char *id)
|
||||||
|
|
||||||
if (find_dev_and_part(id, &dev, &pnum, &part) == 0) {
|
if (find_dev_and_part(id, &dev, &pnum, &part) == 0) {
|
||||||
|
|
||||||
debug("delete_partition: device = %s%d, partition %d = (%s) 0x%08x@0x%08x\n",
|
debug("delete_partition: device = %s%d, partition %d = (%s) 0x%08llx@0x%08llx\n",
|
||||||
MTD_DEV_TYPE(dev->id->type), dev->id->num, pnum,
|
MTD_DEV_TYPE(dev->id->type), dev->id->num, pnum,
|
||||||
part->name, part->size, part->offset);
|
part->name, part->size, part->offset);
|
||||||
|
|
||||||
|
@ -1589,7 +1593,7 @@ static int parse_mtdids(const char *const ids)
|
||||||
struct list_head *entry, *n;
|
struct list_head *entry, *n;
|
||||||
struct mtdids *id_tmp;
|
struct mtdids *id_tmp;
|
||||||
u8 type, num;
|
u8 type, num;
|
||||||
u32 size;
|
u64 size;
|
||||||
int ret = 1;
|
int ret = 1;
|
||||||
|
|
||||||
debug("\n---parse_mtdids---\nmtdids = %s\n\n", ids);
|
debug("\n---parse_mtdids---\nmtdids = %s\n\n", ids);
|
||||||
|
@ -1663,7 +1667,7 @@ static int parse_mtdids(const char *const ids)
|
||||||
id->mtd_id[mtd_id_len - 1] = '\0';
|
id->mtd_id[mtd_id_len - 1] = '\0';
|
||||||
INIT_LIST_HEAD(&id->link);
|
INIT_LIST_HEAD(&id->link);
|
||||||
|
|
||||||
debug("+ id %s%d\t%16d bytes\t%s\n",
|
debug("+ id %s%d\t%16lld bytes\t%s\n",
|
||||||
MTD_DEV_TYPE(id->type), id->num,
|
MTD_DEV_TYPE(id->type), id->num,
|
||||||
id->size, id->mtd_id);
|
id->size, id->mtd_id);
|
||||||
|
|
||||||
|
|
|
@ -167,7 +167,7 @@ bad:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ubi_create_vol(char *volume, int size, int dynamic)
|
static int ubi_create_vol(char *volume, int64_t size, int dynamic)
|
||||||
{
|
{
|
||||||
struct ubi_mkvol_req req;
|
struct ubi_mkvol_req req;
|
||||||
int err;
|
int err;
|
||||||
|
@ -191,7 +191,7 @@ static int ubi_create_vol(char *volume, int size, int dynamic)
|
||||||
printf("verify_mkvol_req failed %d\n", err);
|
printf("verify_mkvol_req failed %d\n", err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
printf("Creating %s volume %s of size %d\n",
|
printf("Creating %s volume %s of size %lld\n",
|
||||||
dynamic ? "dynamic" : "static", volume, size);
|
dynamic ? "dynamic" : "static", volume, size);
|
||||||
/* Call real ubi create volume */
|
/* Call real ubi create volume */
|
||||||
return ubi_create_volume(ubi, &req);
|
return ubi_create_volume(ubi, &req);
|
||||||
|
@ -266,28 +266,15 @@ out_err:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ubi_volume_write(char *volume, void *buf, size_t size)
|
int ubi_volume_continue_write(char *volume, void *buf, size_t size)
|
||||||
{
|
{
|
||||||
int err = 1;
|
int err = 1;
|
||||||
int rsvd_bytes = 0;
|
|
||||||
struct ubi_volume *vol;
|
struct ubi_volume *vol;
|
||||||
|
|
||||||
vol = ubi_find_volume(volume);
|
vol = ubi_find_volume(volume);
|
||||||
if (vol == NULL)
|
if (vol == NULL)
|
||||||
return ENODEV;
|
return ENODEV;
|
||||||
|
|
||||||
rsvd_bytes = vol->reserved_pebs * (ubi->leb_size - vol->data_pad);
|
|
||||||
if (size < 0 || size > rsvd_bytes) {
|
|
||||||
printf("size > volume size! Aborting!\n");
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = ubi_start_update(ubi, vol, size);
|
|
||||||
if (err < 0) {
|
|
||||||
printf("Cannot start volume update\n");
|
|
||||||
return -err;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = ubi_more_update_data(ubi, vol, buf, size);
|
err = ubi_more_update_data(ubi, vol, buf, size);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
printf("Couldnt or partially wrote data\n");
|
printf("Couldnt or partially wrote data\n");
|
||||||
|
@ -314,6 +301,37 @@ int ubi_volume_write(char *volume, void *buf, size_t size)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ubi_volume_begin_write(char *volume, void *buf, size_t size,
|
||||||
|
size_t full_size)
|
||||||
|
{
|
||||||
|
int err = 1;
|
||||||
|
int rsvd_bytes = 0;
|
||||||
|
struct ubi_volume *vol;
|
||||||
|
|
||||||
|
vol = ubi_find_volume(volume);
|
||||||
|
if (vol == NULL)
|
||||||
|
return ENODEV;
|
||||||
|
|
||||||
|
rsvd_bytes = vol->reserved_pebs * (ubi->leb_size - vol->data_pad);
|
||||||
|
if (size < 0 || size > rsvd_bytes) {
|
||||||
|
printf("size > volume size! Aborting!\n");
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ubi_start_update(ubi, vol, full_size);
|
||||||
|
if (err < 0) {
|
||||||
|
printf("Cannot start volume update\n");
|
||||||
|
return -err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ubi_volume_continue_write(volume, buf, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ubi_volume_write(char *volume, void *buf, size_t size)
|
||||||
|
{
|
||||||
|
return ubi_volume_begin_write(volume, buf, size, size);
|
||||||
|
}
|
||||||
|
|
||||||
int ubi_volume_read(char *volume, char *buf, size_t size)
|
int ubi_volume_read(char *volume, char *buf, size_t size)
|
||||||
{
|
{
|
||||||
int err, lnum, off, len, tbuf_size;
|
int err, lnum, off, len, tbuf_size;
|
||||||
|
@ -498,7 +516,7 @@ int ubi_part(char *part_name, const char *vid_header_offset)
|
||||||
|
|
||||||
static int do_ubi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
static int do_ubi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||||
{
|
{
|
||||||
size_t size = 0;
|
int64_t size = 0;
|
||||||
ulong addr = 0;
|
ulong addr = 0;
|
||||||
|
|
||||||
if (argc < 2)
|
if (argc < 2)
|
||||||
|
@ -558,13 +576,13 @@ static int do_ubi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||||
}
|
}
|
||||||
/* E.g., create volume size */
|
/* E.g., create volume size */
|
||||||
if (argc == 4) {
|
if (argc == 4) {
|
||||||
size = simple_strtoul(argv[3], NULL, 16);
|
size = simple_strtoull(argv[3], NULL, 16);
|
||||||
argc--;
|
argc--;
|
||||||
}
|
}
|
||||||
/* Use maximum available size */
|
/* Use maximum available size */
|
||||||
if (!size) {
|
if (!size) {
|
||||||
size = ubi->avail_pebs * ubi->leb_size;
|
size = (int64_t)ubi->avail_pebs * ubi->leb_size;
|
||||||
printf("No size specified -> Using max size (%u)\n", size);
|
printf("No size specified -> Using max size (%lld)\n", size);
|
||||||
}
|
}
|
||||||
/* E.g., create volume */
|
/* E.g., create volume */
|
||||||
if (argc == 3)
|
if (argc == 3)
|
||||||
|
@ -588,9 +606,22 @@ static int do_ubi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||||
addr = simple_strtoul(argv[2], NULL, 16);
|
addr = simple_strtoul(argv[2], NULL, 16);
|
||||||
size = simple_strtoul(argv[4], NULL, 16);
|
size = simple_strtoul(argv[4], NULL, 16);
|
||||||
|
|
||||||
ret = ubi_volume_write(argv[3], (void *)addr, size);
|
if (strlen(argv[1]) == 10 &&
|
||||||
|
strncmp(argv[1] + 5, ".part", 5) == 0) {
|
||||||
|
if (argc < 6) {
|
||||||
|
ret = ubi_volume_continue_write(argv[3],
|
||||||
|
(void *)addr, size);
|
||||||
|
} else {
|
||||||
|
size_t full_size;
|
||||||
|
full_size = simple_strtoul(argv[5], NULL, 16);
|
||||||
|
ret = ubi_volume_begin_write(argv[3],
|
||||||
|
(void *)addr, size, full_size);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = ubi_volume_write(argv[3], (void *)addr, size);
|
||||||
|
}
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
printf("%d bytes written to volume %s\n", size,
|
printf("%lld bytes written to volume %s\n", size,
|
||||||
argv[3]);
|
argv[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -613,7 +644,7 @@ static int do_ubi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc == 3) {
|
if (argc == 3) {
|
||||||
printf("Read %d bytes from volume %s to %lx\n", size,
|
printf("Read %lld bytes from volume %s to %lx\n", size,
|
||||||
argv[3], addr);
|
argv[3], addr);
|
||||||
|
|
||||||
return ubi_volume_read(argv[3], (char *)addr, size);
|
return ubi_volume_read(argv[3], (char *)addr, size);
|
||||||
|
@ -636,6 +667,8 @@ U_BOOT_CMD(
|
||||||
" - create volume name with size\n"
|
" - create volume name with size\n"
|
||||||
"ubi write[vol] address volume size"
|
"ubi write[vol] address volume size"
|
||||||
" - Write volume from address with size\n"
|
" - Write volume from address with size\n"
|
||||||
|
"ubi write.part address volume size [fullsize]\n"
|
||||||
|
" - Write part of a volume from address\n"
|
||||||
"ubi read[vol] address volume [size]"
|
"ubi read[vol] address volume [size]"
|
||||||
" - Read volume to address with size\n"
|
" - Read volume to address with size\n"
|
||||||
"ubi remove[vol] volume"
|
"ubi remove[vol] volume"
|
||||||
|
|
|
@ -14,6 +14,8 @@ ubi part [part] [offset]
|
||||||
ubi info [l[ayout]] - Display volume and ubi layout information
|
ubi info [l[ayout]] - Display volume and ubi layout information
|
||||||
ubi create[vol] volume [size] [type] - create volume name with size
|
ubi create[vol] volume [size] [type] - create volume name with size
|
||||||
ubi write[vol] address volume size - Write volume from address with size
|
ubi write[vol] address volume size - Write volume from address with size
|
||||||
|
ubi write.part address volume size [fullsize]
|
||||||
|
- Write part of a volume from address
|
||||||
ubi read[vol] address volume [size] - Read volume to address with size
|
ubi read[vol] address volume [size] - Read volume to address with size
|
||||||
ubi remove[vol] volume - Remove volume
|
ubi remove[vol] volume - Remove volume
|
||||||
[Legends]
|
[Legends]
|
||||||
|
@ -77,6 +79,7 @@ ubi createvol Create UBI volume on UBI device
|
||||||
ubi removevol Remove UBI volume from UBI device
|
ubi removevol Remove UBI volume from UBI device
|
||||||
ubi read Read data from UBI volume to memory
|
ubi read Read data from UBI volume to memory
|
||||||
ubi write Write data from memory to UBI volume
|
ubi write Write data from memory to UBI volume
|
||||||
|
ubi write.part Write data from memory to UBI volume, in parts
|
||||||
|
|
||||||
|
|
||||||
Here a few examples on the usage:
|
Here a few examples on the usage:
|
||||||
|
|
|
@ -217,11 +217,23 @@ int mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||||
int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
|
int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
|
||||||
u_char *buf)
|
u_char *buf)
|
||||||
{
|
{
|
||||||
|
int ret_code;
|
||||||
if (from < 0 || from > mtd->size || len > mtd->size - from)
|
if (from < 0 || from > mtd->size || len > mtd->size - from)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (!len)
|
if (!len)
|
||||||
return 0;
|
return 0;
|
||||||
return mtd->_read(mtd, from, len, retlen, buf);
|
|
||||||
|
/*
|
||||||
|
* In the absence of an error, drivers return a non-negative integer
|
||||||
|
* representing the maximum number of bitflips that were corrected on
|
||||||
|
* any one ecc region (if applicable; zero otherwise).
|
||||||
|
*/
|
||||||
|
ret_code = mtd->_read(mtd, from, len, retlen, buf);
|
||||||
|
if (unlikely(ret_code < 0))
|
||||||
|
return ret_code;
|
||||||
|
if (mtd->ecc_strength == 0)
|
||||||
|
return 0; /* device lacks ecc */
|
||||||
|
return ret_code >= mtd->bitflip_threshold ? -EUCLEAN : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
|
int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
|
||||||
|
|
|
@ -53,12 +53,12 @@ static int part_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
|
|
||||||
stats = part->master->ecc_stats;
|
stats = part->master->ecc_stats;
|
||||||
res = mtd_read(part->master, from + part->offset, len, retlen, buf);
|
res = mtd_read(part->master, from + part->offset, len, retlen, buf);
|
||||||
if (unlikely(res)) {
|
if (unlikely(mtd_is_eccerr(res)))
|
||||||
if (mtd_is_bitflip(res))
|
mtd->ecc_stats.failed +=
|
||||||
mtd->ecc_stats.corrected += part->master->ecc_stats.corrected - stats.corrected;
|
part->master->ecc_stats.failed - stats.failed;
|
||||||
if (mtd_is_eccerr(res))
|
else
|
||||||
mtd->ecc_stats.failed += part->master->ecc_stats.failed - stats.failed;
|
mtd->ecc_stats.corrected +=
|
||||||
}
|
part->master->ecc_stats.corrected - stats.corrected;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1238,6 +1238,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
|
||||||
mtd->oobavail : mtd->oobsize;
|
mtd->oobavail : mtd->oobsize;
|
||||||
|
|
||||||
uint8_t *bufpoi, *oob, *buf;
|
uint8_t *bufpoi, *oob, *buf;
|
||||||
|
unsigned int max_bitflips = 0;
|
||||||
|
|
||||||
stats = mtd->ecc_stats;
|
stats = mtd->ecc_stats;
|
||||||
|
|
||||||
|
@ -1265,7 +1266,10 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
|
||||||
|
|
||||||
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
|
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
|
||||||
|
|
||||||
/* Now read the page into the buffer */
|
/*
|
||||||
|
* Now read the page into the buffer. Absent an error,
|
||||||
|
* the read methods return max bitflips per ecc step.
|
||||||
|
*/
|
||||||
if (unlikely(ops->mode == MTD_OPS_RAW))
|
if (unlikely(ops->mode == MTD_OPS_RAW))
|
||||||
ret = chip->ecc.read_page_raw(mtd, chip, bufpoi,
|
ret = chip->ecc.read_page_raw(mtd, chip, bufpoi,
|
||||||
oob_required,
|
oob_required,
|
||||||
|
@ -1284,15 +1288,19 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
max_bitflips = max_t(unsigned int, max_bitflips, ret);
|
||||||
|
|
||||||
/* Transfer not aligned data */
|
/* Transfer not aligned data */
|
||||||
if (!aligned) {
|
if (!aligned) {
|
||||||
if (!NAND_HAS_SUBPAGE_READ(chip) && !oob &&
|
if (!NAND_HAS_SUBPAGE_READ(chip) && !oob &&
|
||||||
!(mtd->ecc_stats.failed - stats.failed) &&
|
!(mtd->ecc_stats.failed - stats.failed) &&
|
||||||
(ops->mode != MTD_OPS_RAW))
|
(ops->mode != MTD_OPS_RAW)) {
|
||||||
chip->pagebuf = realpage;
|
chip->pagebuf = realpage;
|
||||||
else
|
chip->pagebuf_bitflips = ret;
|
||||||
|
} else {
|
||||||
/* Invalidate page cache */
|
/* Invalidate page cache */
|
||||||
chip->pagebuf = -1;
|
chip->pagebuf = -1;
|
||||||
|
}
|
||||||
memcpy(buf, chip->buffers->databuf + col, bytes);
|
memcpy(buf, chip->buffers->databuf + col, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1310,6 +1318,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
|
||||||
} else {
|
} else {
|
||||||
memcpy(buf, chip->buffers->databuf + col, bytes);
|
memcpy(buf, chip->buffers->databuf + col, bytes);
|
||||||
buf += bytes;
|
buf += bytes;
|
||||||
|
max_bitflips = max_t(unsigned int, max_bitflips,
|
||||||
|
chip->pagebuf_bitflips);
|
||||||
}
|
}
|
||||||
|
|
||||||
readlen -= bytes;
|
readlen -= bytes;
|
||||||
|
@ -1341,7 +1351,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
|
||||||
if (mtd->ecc_stats.failed - stats.failed)
|
if (mtd->ecc_stats.failed - stats.failed)
|
||||||
return -EBADMSG;
|
return -EBADMSG;
|
||||||
|
|
||||||
return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
|
return max_bitflips;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -969,7 +969,8 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
|
||||||
if (mtd->ecc_stats.failed - stats.failed)
|
if (mtd->ecc_stats.failed - stats.failed)
|
||||||
return -EBADMSG;
|
return -EBADMSG;
|
||||||
|
|
||||||
return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
|
/* return max bitflips per ecc step; ONENANDs correct 1 bit only */
|
||||||
|
return mtd->ecc_stats.corrected != stats.corrected ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -32,8 +32,8 @@ struct part_info {
|
||||||
struct list_head link;
|
struct list_head link;
|
||||||
char *name; /* partition name */
|
char *name; /* partition name */
|
||||||
u8 auto_name; /* set to 1 for generated name */
|
u8 auto_name; /* set to 1 for generated name */
|
||||||
u32 size; /* total size of the partition */
|
u64 size; /* total size of the partition */
|
||||||
u32 offset; /* offset within device */
|
u64 offset; /* offset within device */
|
||||||
void *jffs2_priv; /* used internaly by jffs2 */
|
void *jffs2_priv; /* used internaly by jffs2 */
|
||||||
u32 mask_flags; /* kernel MTD mask flags */
|
u32 mask_flags; /* kernel MTD mask flags */
|
||||||
u32 sector_size; /* size of sector */
|
u32 sector_size; /* size of sector */
|
||||||
|
@ -44,7 +44,7 @@ struct mtdids {
|
||||||
struct list_head link;
|
struct list_head link;
|
||||||
u8 type; /* device type */
|
u8 type; /* device type */
|
||||||
u8 num; /* device number */
|
u8 num; /* device number */
|
||||||
u32 size; /* device size */
|
u64 size; /* device size */
|
||||||
char *mtd_id; /* linux kernel device id */
|
char *mtd_id; /* linux kernel device id */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -464,6 +464,8 @@ struct nand_buffers {
|
||||||
* @pagemask: [INTERN] page number mask = number of (pages / chip) - 1
|
* @pagemask: [INTERN] page number mask = number of (pages / chip) - 1
|
||||||
* @pagebuf: [INTERN] holds the pagenumber which is currently in
|
* @pagebuf: [INTERN] holds the pagenumber which is currently in
|
||||||
* data_buf.
|
* data_buf.
|
||||||
|
* @pagebuf_bitflips: [INTERN] holds the bitflip count for the page which is
|
||||||
|
* currently in data_buf.
|
||||||
* @subpagesize: [INTERN] holds the subpagesize
|
* @subpagesize: [INTERN] holds the subpagesize
|
||||||
* @onfi_version: [INTERN] holds the chip ONFI version (BCD encoded),
|
* @onfi_version: [INTERN] holds the chip ONFI version (BCD encoded),
|
||||||
* non 0 if ONFI supported.
|
* non 0 if ONFI supported.
|
||||||
|
@ -531,6 +533,7 @@ struct nand_chip {
|
||||||
uint64_t chipsize;
|
uint64_t chipsize;
|
||||||
int pagemask;
|
int pagemask;
|
||||||
int pagebuf;
|
int pagebuf;
|
||||||
|
unsigned int pagebuf_bitflips;
|
||||||
int subpagesize;
|
int subpagesize;
|
||||||
uint8_t cellinfo;
|
uint8_t cellinfo;
|
||||||
int badblockpos;
|
int badblockpos;
|
||||||
|
|
Loading…
Add table
Reference in a new issue