X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=common%2Fcmd_jffs2.c;h=0818ea811b2be3a96116fdd8a45f4ff25e6e332f;hb=b5b004ad8a0ac6f98bd5708ec8b22fbddd1c1042;hp=7ab6e9ca7a1dddac15f112c2d7c4f40a548931af;hpb=87b8bd5aed0d2a71cf77c7178d67a370a0f68612;p=oweals%2Fu-boot.git diff --git a/common/cmd_jffs2.c b/common/cmd_jffs2.c index 7ab6e9ca7a..0818ea811b 100644 --- a/common/cmd_jffs2.c +++ b/common/cmd_jffs2.c @@ -51,7 +51,7 @@ * mtdids=[,,...] * * := = - * := 'nand'|'nor' + * := 'nand'|'nor'|'onenand' * := mtd device number, 0... * := unique device tag used by linux kernel to find mtd device (mtd->name) * @@ -91,19 +91,30 @@ #include #include #include -#include #include #include +#include -#if (CONFIG_COMMANDS & CFG_CMD_JFFS2) +#if defined(CONFIG_CMD_NAND) +#ifdef CONFIG_NAND_LEGACY +#include +#else /* !CONFIG_NAND_LEGACY */ +#include +#include +#endif /* !CONFIG_NAND_LEGACY */ +#endif -#include +#if defined(CONFIG_CMD_ONENAND) +#include +#include +#include +#endif /* enable/disable debugging messages */ -#define DEBUG -#undef DEBUG +#define DEBUG_JFFS +#undef DEBUG_JFFS -#ifdef DEBUG +#ifdef DEBUG_JFFS # define DEBUGF(fmt, args...) printf(fmt ,##args) #else # define DEBUGF(fmt, args...) @@ -123,7 +134,7 @@ /* this flag needs to be set in part_info struct mask_flags * field for read-only partitions */ -#define MTD_WRITEABLE 1 +#define MTD_WRITEABLE_CMD 1 #ifdef CONFIG_JFFS2_CMDLINE /* default values for mtdids and mtdparts variables */ @@ -163,10 +174,19 @@ struct list_head devices; static struct mtd_device *current_dev = NULL; static u8 current_partnum = 0; +#if defined(CONFIG_CMD_CRAMFS) extern int cramfs_check (struct part_info *info); extern int cramfs_load (char *loadoffset, struct part_info *info, char *filename); extern int cramfs_ls (struct part_info *info, char *filename); extern int cramfs_info (struct part_info *info); +#else +/* defining empty macros for function names is ugly but avoids ifdef clutter + * all over the code */ +#define cramfs_check(x) (0) +#define cramfs_load(x,y,z) (-1) +#define cramfs_ls(x,y) (0) +#define cramfs_info(x) (0) +#endif static struct part_info* jffs2_part_info(struct mtd_device *dev, unsigned int part_num); @@ -228,13 +248,53 @@ static void memsize_format(char *buf, u32 size) #define SIZE_KB ((u32)1024) if ((size % SIZE_GB) == 0) - sprintf(buf, "%lug", size/SIZE_GB); + sprintf(buf, "%ug", size/SIZE_GB); else if ((size % SIZE_MB) == 0) - sprintf(buf, "%lum", size/SIZE_MB); + sprintf(buf, "%um", size/SIZE_MB); else if (size % SIZE_KB == 0) - sprintf(buf, "%luk", size/SIZE_KB); + sprintf(buf, "%uk", size/SIZE_KB); else - sprintf(buf, "%lu", size); + sprintf(buf, "%u", size); +} + +/** + * This routine does global indexing of all partitions. Resulting index for + * current partition is saved in 'mtddevnum'. Current partition name in + * 'mtddevname'. + */ +static void index_partitions(void) +{ + char buf[16]; + u16 mtddevnum; + struct part_info *part; + struct list_head *dentry; + struct mtd_device *dev; + + DEBUGF("--- index partitions ---\n"); + + if (current_dev) { + mtddevnum = 0; + list_for_each(dentry, &devices) { + dev = list_entry(dentry, struct mtd_device, link); + if (dev == current_dev) { + mtddevnum += current_partnum; + sprintf(buf, "%d", mtddevnum); + setenv("mtddevnum", buf); + break; + } + mtddevnum += dev->num_parts; + } + + part = jffs2_part_info(current_dev, current_partnum); + setenv("mtddevname", part->name); + + DEBUGF("=> mtddevnum %d,\n=> mtddevname %s\n", mtddevnum, part->name); + } else { + setenv("mtddevnum", NULL); + setenv("mtddevname", NULL); + + DEBUGF("=> mtddevnum NULL\n=> mtddevname NULL\n"); + } } /** @@ -260,6 +320,7 @@ static void current_save(void) DEBUGF("=> partition NULL\n"); } + index_partitions(); } /** @@ -273,16 +334,20 @@ static void current_save(void) */ static int part_validate_nor(struct mtdids *id, struct part_info *part) { -#if (CONFIG_COMMANDS & CFG_CMD_FLASH) +#if defined(CONFIG_CMD_FLASH) /* info for FLASH chips */ - extern flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; + extern flash_info_t flash_info[]; flash_info_t *flash; int offset_aligned; - u32 end_offset; + u32 end_offset, sector_size = 0; int i; flash = &flash_info[id->num]; + /* size of last sector */ + part->sector_size = flash->size - + (flash->start[flash->sector_count-1] - flash->start[0]); + offset_aligned = 0; for (i = 0; i < flash->sector_count; i++) { if ((flash->start[i] - flash->start[0]) == part->offset) { @@ -297,12 +362,18 @@ static int part_validate_nor(struct mtdids *id, struct part_info *part) } end_offset = part->offset + part->size; + offset_aligned = 0; for (i = 0; i < flash->sector_count; i++) { + if (i) { + sector_size = flash->start[i] - flash->start[i-1]; + if (part->sector_size < sector_size) + part->sector_size = sector_size; + } if ((flash->start[i] - flash->start[0]) == end_offset) - return 0; + offset_aligned = 1; } - if (flash->size == end_offset) + if (offset_aligned || flash->size == end_offset) return 0; printf("%s%d: partition (%s) size alignment incorrect\n", @@ -322,12 +393,13 @@ static int part_validate_nor(struct mtdids *id, struct part_info *part) */ static int part_validate_nand(struct mtdids *id, struct part_info *part) { -#if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND) +#if defined(CONFIG_JFFS2_NAND) && defined(CONFIG_CMD_NAND) /* info for NAND chips */ - extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE]; - struct nand_chip *nand; + nand_info_t *nand; - nand = &nand_dev_desc[id->num]; + nand = &nand_info[id->num]; + + part->sector_size = nand->erasesize; if ((unsigned long)(part->offset) % nand->erasesize) { printf("%s%d: partition (%s) start offset alignment incorrect\n", @@ -347,6 +419,45 @@ static int part_validate_nand(struct mtdids *id, struct part_info *part) #endif } +/** + * Performs sanity check for supplied OneNAND flash partition. + * Table of existing OneNAND flash devices is searched and partition device + * is located. Alignment with the granularity of nand erasesize is verified. + * + * @param id of the parent device + * @param part partition to validate + * @return 0 if partition is valid, 1 otherwise + */ +static int part_validate_onenand(struct mtdids *id, struct part_info *part) +{ +#if defined(CONFIG_CMD_ONENAND) + /* info for OneNAND chips */ + struct mtd_info *mtd; + + mtd = &onenand_mtd; + + part->sector_size = mtd->erasesize; + + if ((unsigned long)(part->offset) % mtd->erasesize) { + printf("%s%d: partition (%s) start offset" + "alignment incorrect\n", + MTD_DEV_TYPE(id->type), id->num, part->name); + return 1; + } + + if (part->size % mtd->erasesize) { + printf("%s%d: partition (%s) size alignment incorrect\n", + MTD_DEV_TYPE(id->type), id->num, part->name); + return 1; + } + + return 0; +#else + return 1; +#endif +} + + /** * Performs sanity check for supplied partition. Offset and size are verified * to be within valid range. Partition type is checked and either @@ -363,7 +474,7 @@ static int part_validate(struct mtdids *id, struct part_info *part) part->size = id->size - part->offset; if (part->offset > id->size) { - printf("%s: offset %08lx beyond flash size %08lx\n", + printf("%s: offset %08x beyond flash size %08x\n", id->mtd_id, part->offset, id->size); return 1; } @@ -383,6 +494,8 @@ static int part_validate(struct mtdids *id, struct part_info *part) return part_validate_nand(id, part); else if (id->type == MTD_DEV_TYPE_NOR) return part_validate_nor(id, part); + else if (id->type == MTD_DEV_TYPE_ONENAND) + return part_validate_onenand(id, part); else DEBUGF("part_validate: invalid dev type\n"); @@ -398,6 +511,8 @@ static int part_validate(struct mtdids *id, struct part_info *part) */ static int part_del(struct mtd_device *dev, struct part_info *part) { + u8 current_save_needed = 0; + /* if there is only one partition, remove whole device */ if (dev->num_parts == 1) return device_del(dev); @@ -414,20 +529,25 @@ static int part_del(struct mtd_device *dev, struct part_info *part) if (curr_pi == part) { printf("current partition deleted, resetting current to 0\n"); current_partnum = 0; - current_save(); } else if (part->offset <= curr_pi->offset) { current_partnum--; - current_save(); } + current_save_needed = 1; } } - +#ifdef CONFIG_NAND_LEGACY jffs2_free_cache(part); +#endif list_del(&part->link); free(part); dev->num_parts--; + if (current_save_needed > 0) + current_save(); + else + index_partitions(); + return 0; } @@ -445,7 +565,9 @@ static void part_delall(struct list_head *head) list_for_each_safe(entry, n, head) { part_tmp = list_entry(entry, struct part_info, link); +#ifdef CONFIG_NAND_LEGACY jffs2_free_cache(part_tmp); +#endif list_del(entry); free(part_tmp); } @@ -469,6 +591,8 @@ static int part_sort_add(struct mtd_device *dev, struct part_info *part) if (list_empty(&dev->parts)) { DEBUGF("part_sort_add: list empty\n"); list_add(&part->link, &dev->parts); + dev->num_parts++; + index_partitions(); return 0; } @@ -492,18 +616,23 @@ static int part_sort_add(struct mtd_device *dev, struct part_info *part) if (new_pi->offset <= pi->offset) { list_add_tail(&part->link, entry); + dev->num_parts++; if (curr_pi && (pi->offset <= curr_pi->offset)) { /* we are modyfing partitions for the current * device, update current */ current_partnum++; current_save(); + } else { + index_partitions(); } - return 0; } } + list_add_tail(&part->link, &dev->parts); + dev->num_parts++; + index_partitions(); return 0; } @@ -524,7 +653,6 @@ static int part_add(struct mtd_device *dev, struct part_info *part) if (part_sort_add(dev, part) != 0) return 1; - dev->num_parts++; return 0; } @@ -594,7 +722,7 @@ static int part_parse(const char *const partdef, const char **ret, struct part_i /* test for options */ mask_flags = 0; if (strncmp(p, "ro", 2) == 0) { - mask_flags |= MTD_WRITEABLE; + mask_flags |= MTD_WRITEABLE_CMD; p += 2; } @@ -657,32 +785,45 @@ static int part_parse(const char *const partdef, const char **ret, struct part_i static int device_validate(u8 type, u8 num, u32 *size) { if (type == MTD_DEV_TYPE_NOR) { -#if (CONFIG_COMMANDS & CFG_CMD_FLASH) - if (num < CFG_MAX_FLASH_BANKS) { - extern flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; +#if defined(CONFIG_CMD_FLASH) + if (num < CONFIG_SYS_MAX_FLASH_BANKS) { + extern flash_info_t flash_info[]; *size = flash_info[num].size; + return 0; } printf("no such FLASH device: %s%d (valid range 0 ... %d\n", - MTD_DEV_TYPE(type), num, CFG_MAX_FLASH_BANKS - 1); + MTD_DEV_TYPE(type), num, CONFIG_SYS_MAX_FLASH_BANKS - 1); #else printf("support for FLASH devices not present\n"); #endif } else if (type == MTD_DEV_TYPE_NAND) { -#if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND) - if (num < CFG_MAX_NAND_DEVICE) { - extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE]; +#if defined(CONFIG_JFFS2_NAND) && defined(CONFIG_CMD_NAND) + if (num < CONFIG_SYS_MAX_NAND_DEVICE) { +#ifndef CONFIG_NAND_LEGACY + *size = nand_info[num].size; +#else + extern struct nand_chip nand_dev_desc[CONFIG_SYS_MAX_NAND_DEVICE]; *size = nand_dev_desc[num].totlen; +#endif return 0; } printf("no such NAND device: %s%d (valid range 0 ... %d)\n", - MTD_DEV_TYPE(type), num, CFG_MAX_NAND_DEVICE - 1); + MTD_DEV_TYPE(type), num, CONFIG_SYS_MAX_NAND_DEVICE - 1); #else printf("support for NAND devices not present\n"); #endif - } + } else if (type == MTD_DEV_TYPE_ONENAND) { +#if defined(CONFIG_CMD_ONENAND) + *size = onenand_mtd.size; + return 0; +#else + printf("support for OneNAND devices not present\n"); +#endif + } else + printf("Unknown defice type %d\n", type); return 1; } @@ -735,9 +876,10 @@ static int device_del(struct mtd_device *dev) current_partnum = 0; } current_save(); + return 0; } - + index_partitions(); return 0; } @@ -771,13 +913,20 @@ static struct mtd_device* device_find(u8 type, u8 num) */ static void device_add(struct mtd_device *dev) { + u8 current_save_needed = 0; + if (list_empty(&devices)) { current_dev = dev; current_partnum = 0; - current_save(); + current_save_needed = 1; } list_add_tail(&dev->link, &devices); + + if (current_save_needed > 0) + current_save(); + else + index_partitions(); } /** @@ -896,7 +1045,7 @@ static int device_parse(const char *const mtd_dev, const char **ret, struct mtd_ } memset(dev, 0, sizeof(struct mtd_device)); dev->id = id; - dev->num_parts = num_parts; + dev->num_parts = 0; /* part_sort_add increments num_parts */ INIT_LIST_HEAD(&dev->parts); INIT_LIST_HEAD(&dev->link); @@ -921,7 +1070,7 @@ static int device_parse(const char *const mtd_dev, const char **ret, struct mtd_ * * @return 0 on success, 1 otherwise */ -static int devices_init(void) +static int jffs2_devices_init(void) { last_parts[0] = '\0'; current_dev = NULL; @@ -984,8 +1133,8 @@ static struct mtdids* id_find_by_mtd_id(const char *mtd_id, unsigned int mtd_id_ #endif /* #ifdef CONFIG_JFFS2_CMDLINE */ /** - * Parse device id string := 'nand'|'nor', return device - * type and number. + * Parse device id string := 'nand'|'nor'|'onenand', + * return device type and number. * * @param id string describing device id * @param ret_id output pointer to next char after parse completes (output) @@ -1004,6 +1153,9 @@ int id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num) } else if (strncmp(p, "nor", 3) == 0) { *dev_type = MTD_DEV_TYPE_NOR; p += 3; + } else if (strncmp(p, "onenand", 7) == 0) { + *dev_type = MTD_DEV_TYPE_ONENAND; + p += 7; } else { printf("incorrect device type in %s\n", id); return 1; @@ -1109,7 +1261,7 @@ static int generate_mtdparts(char *buf, u32 buflen) } /* ro mask flag */ - if (part->mask_flags && MTD_WRITEABLE) { + if (part->mask_flags && MTD_WRITEABLE_CMD) { len = 2; if (len > maxlen) goto cleanup; @@ -1193,7 +1345,7 @@ static void list_partitions(void) part_num = 0; list_for_each(pentry, &dev->parts) { part = list_entry(pentry, struct part_info, link); - printf(" %d: %-22s\t0x%08x\t0x%08x\t%d\n", + printf("%2d: %-20s0x%08x\t0x%08x\t%d\n", part_num, part->name, part->size, part->offset, part->mask_flags); @@ -1207,7 +1359,7 @@ static void list_partitions(void) if (current_dev) { part = jffs2_part_info(current_dev, current_partnum); if (part) { - printf("\nactive partition: %s%d,%d - (%s) 0x%08lx @ 0x%08lx\n", + printf("\nactive partition: %s%d,%d - (%s) 0x%08x @ 0x%08x\n", MTD_DEV_TYPE(current_dev->id->type), current_dev->id->num, current_partnum, part->name, part->size, part->offset); @@ -1225,7 +1377,7 @@ static void list_partitions(void) * Given partition identifier in form of , find * corresponding device and verify partition number. * - * @param id string describing device and partition + * @param id string describing device and partition or partition name * @param dev pointer to the requested device (output) * @param part_num verified partition number (output) * @param part pointer to requested partition (output) @@ -1234,11 +1386,23 @@ static void list_partitions(void) int find_dev_and_part(const char *id, struct mtd_device **dev, u8 *part_num, struct part_info **part) { + struct list_head *dentry, *pentry; u8 type, dnum, pnum; const char *p; DEBUGF("--- find_dev_and_part ---\nid = %s\n", id); + list_for_each(dentry, &devices) { + *part_num = 0; + *dev = list_entry(dentry, struct mtd_device, link); + list_for_each(pentry, &(*dev)->parts) { + *part = list_entry(pentry, struct part_info, link); + if (strcmp((*part)->name, id) == 0) + return 0; + (*part_num)++; + } + } + p = id; *dev = NULL; *part = NULL; @@ -1321,12 +1485,12 @@ static int parse_mtdparts(const char *const mtdparts) DEBUGF("\n---parse_mtdparts---\nmtdparts = %s\n\n", p); /* delete all devices and partitions */ - if (devices_init() != 0) { + if (jffs2_devices_init() != 0) { printf("could not initialise device list\n"); return err; } - /* re-read 'mtdparts' variable, devices_init may be updating env */ + /* re-read 'mtdparts' variable, jffs2_devices_init may be updating env */ p = getenv("mtdparts"); if (strncmp(p, "mtdparts=", 9) != 0) { @@ -1396,7 +1560,7 @@ static int parse_mtdids(const char *const ids) while(p && (*p != '\0')) { ret = 1; - /* parse 'nor'|'nand' */ + /* parse 'nor'|'nand'|'onenand' */ if (id_parse(p, &p, &type, &num) != 0) break; @@ -1548,7 +1712,7 @@ int mtdparts_init(void) ids_changed = 1; if (parse_mtdids(ids) != 0) { - device_delall(&devices); + jffs2_devices_init(); return 1; } @@ -1581,7 +1745,7 @@ int mtdparts_init(void) /* mtdparts variable was reset to NULL, delete all devices/partitions */ if (!parts && (last_parts[0] != '\0')) - return devices_init(); + return jffs2_devices_init(); /* do not process current partition if mtdparts variable is null */ if (!parts) @@ -1613,6 +1777,96 @@ int mtdparts_init(void) * a single device configuration. */ +/** + * Calculate sector size. + * + * @return sector size + */ +static inline u32 get_part_sector_size_nand(struct mtdids *id) +{ +#if defined(CONFIG_JFFS2_NAND) && defined(CONFIG_CMD_NAND) +#if defined(CONFIG_NAND_LEGACY) + extern struct nand_chip nand_dev_desc[CONFIG_SYS_MAX_NAND_DEVICE]; + + return nand_dev_desc[id->num].erasesize; +#else + nand_info_t *nand; + + nand = &nand_info[id->num]; + + return nand->erasesize; +#endif +#else + BUG(); + return 0; +#endif +} + +static inline u32 get_part_sector_size_nor(struct mtdids *id, struct part_info *part) +{ +#if defined(CONFIG_CMD_FLASH) + extern flash_info_t flash_info[]; + + u32 end_phys, start_phys, sector_size = 0, size = 0; + int i; + flash_info_t *flash; + + flash = &flash_info[id->num]; + + start_phys = flash->start[0] + part->offset; + end_phys = start_phys + part->size; + + for (i = 0; i < flash->sector_count; i++) { + if (flash->start[i] >= end_phys) + break; + + if (flash->start[i] >= start_phys) { + if (i == flash->sector_count - 1) { + size = flash->start[0] + flash->size - flash->start[i]; + } else { + size = flash->start[i+1] - flash->start[i]; + } + + if (sector_size < size) + sector_size = size; + } + } + + return sector_size; +#else + BUG(); + return 0; +#endif +} + +static inline u32 get_part_sector_size_onenand(void) +{ +#if defined(CONFIG_CMD_ONENAND) + struct mtd_info *mtd; + + mtd = &onenand_mtd; + + return mtd->erasesize; +#else + BUG(); + return 0; +#endif +} + +static inline u32 get_part_sector_size(struct mtdids *id, struct part_info *part) +{ + if (id->type == MTD_DEV_TYPE_NAND) + return get_part_sector_size_nand(id); + else if (id->type == MTD_DEV_TYPE_NOR) + return get_part_sector_size_nor(id, part); + else if (id->type == MTD_DEV_TYPE_ONENAND) + return get_part_sector_size_onenand(); + else + DEBUGF("Error: Unknown device type.\n"); + + return 0; +} + /** * Parse and initialize global mtdids mapping and create global * device/partition list. @@ -1682,6 +1936,8 @@ int mtdparts_init(void) part->offset = 0x00000000; #endif + part->sector_size = get_part_sector_size(id, part); + part->dev = current_dev; INIT_LIST_HEAD(&part->link); @@ -1955,8 +2211,8 @@ int do_jffs2_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) setenv("mtdparts", NULL); - /* devices_init() calls current_save() */ - return devices_init(); + /* jffs2_devices_init() calls current_save() */ + return jffs2_devices_init(); } } @@ -2088,7 +2344,7 @@ U_BOOT_CMD( "'mtdids' - linux kernel mtd device id <-> u-boot device id mapping\n\n" "mtdids=[,,...]\n\n" " := =\n" - " := 'nand'|'nor'\n" + " := 'nand'|'nor'|'onenand'\n" " := mtd device number, 0...\n" " := unique device tag used by linux kernel to find mtd device (mtd->name)\n\n" "'mtdparts' - partition list\n\n" @@ -2104,5 +2360,3 @@ U_BOOT_CMD( #endif /* #ifdef CONFIG_JFFS2_CMDLINE */ /***************************************************/ - -#endif /* CFG_CMD_JFFS2 */