Dear Kyungmin Park, Some more comments after testing your patches.
2008/10/28 Kyungmin Park <[EMAIL PROTECTED]>: > UBI (Latin: "where?") stands for "Unsorted Block Images". It is a volume > management system for flash devices which manages multiple logical volumes on > a single physical flash device and spreads the I/O load (i.e, wear-leveling) > across the whole flash chip. > > In a sense, UBI may be compared to the Logical Volume Manager (LVM). Whereas > LVM maps logical sectors to physical sectors, UBI maps logical eraseblocks to > physical eraseblocks. But besides the mapping, UBI implements global > wear-leveling and I/O errors handling. > > For more details, Please visit the following URL. > http://www.linux-mtd.infradead.org/doc/ubi.html > > Signed-off-by: Kyungmin Park <[EMAIL PROTECTED]> > --- > diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c > new file mode 100644 > index 0000000..b6f8699 > --- /dev/null > +++ b/drivers/mtd/ubi/build.c > +static int io_init(struct ubi_device *ubi) > +{ > + if (ubi->mtd->numeraseregions != 0) { > + /* > + * Some flashes have several erase regions. Different regions > + * may have different eraseblock size and other > + * characteristics. It looks like mostly multi-region flashes > + * have one "main" region and one or more small regions to > + * store boot loader code or boot parameters or whatever. I > + * guess we should just pick the largest region. But this is > + * not implemented. > + */ > + ubi_err("multiple regions, not implemented"); > + return -EINVAL; > + } > + > + if (ubi->vid_hdr_offset < 0) > + return -EINVAL; > + > + /* > + * Note, in this implementation we support MTD devices with 0x7FFFFFFF > + * physical eraseblocks maximum. > + */ > + > + ubi->peb_size = ubi->mtd->erasesize; > + ubi->peb_count = ubi->mtd->size / ubi->mtd->erasesize; > + ubi->flash_size = ubi->mtd->size; > + > + if (ubi->mtd->block_isbad && ubi->mtd->block_markbad) > + ubi->bad_allowed = 1; > + > + ubi->min_io_size = ubi->mtd->writesize; > + ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft; > + > + /* > + * Make sure minimal I/O unit is power of 2. Note, there is no > + * fundamental reason for this assumption. It is just an optimization > + * which allows us to avoid costly division operations. > + */ > + if (!is_power_of_2(ubi->min_io_size)) { > + ubi_err("min. I/O unit (%d) is not power of 2", > + ubi->min_io_size); > + return -EINVAL; > + } > + > + ubi_assert(ubi->hdrs_min_io_size > 0); > + ubi_assert(ubi->hdrs_min_io_size <= ubi->min_io_size); > + ubi_assert(ubi->min_io_size % ubi->hdrs_min_io_size == 0); > + > + /* Calculate default aligned sizes of EC and VID headers */ > + ubi->ec_hdr_alsize = ALIGN(UBI_EC_HDR_SIZE, ubi->hdrs_min_io_size); > + ubi->vid_hdr_alsize = ALIGN(UBI_VID_HDR_SIZE, ubi->hdrs_min_io_size); > + > + dbg_msg("min_io_size %d", ubi->min_io_size); > + dbg_msg("hdrs_min_io_size %d", ubi->hdrs_min_io_size); > + dbg_msg("ec_hdr_alsize %d", ubi->ec_hdr_alsize); > + dbg_msg("vid_hdr_alsize %d", ubi->vid_hdr_alsize); > + > + if (ubi->vid_hdr_offset == 0) > + /* Default offset */ > + ubi->vid_hdr_offset = ubi->vid_hdr_aloffset = > + ubi->ec_hdr_alsize; > + else { > + ubi->vid_hdr_aloffset = ubi->vid_hdr_offset & > + ~(ubi->hdrs_min_io_size - 1); > + ubi->vid_hdr_shift = ubi->vid_hdr_offset - > + ubi->vid_hdr_aloffset; > + } > + > + /* Similar for the data offset */ > + ubi->leb_start = ubi->vid_hdr_offset + UBI_EC_HDR_SIZE; > + ubi->leb_start = ALIGN(ubi->leb_start, ubi->min_io_size); > + > + dbg_msg("vid_hdr_offset %d", ubi->vid_hdr_offset); > + dbg_msg("vid_hdr_aloffset %d", ubi->vid_hdr_aloffset); > + dbg_msg("vid_hdr_shift %d", ubi->vid_hdr_shift); > + dbg_msg("leb_start %d", ubi->leb_start); > + > + /* The shift must be aligned to 32-bit boundary */ > + if (ubi->vid_hdr_shift % 4) { > + ubi_err("unaligned VID header shift %d", > + ubi->vid_hdr_shift); > + return -EINVAL; > + } > + > + /* Check sanity */ > + if (ubi->vid_hdr_offset < UBI_EC_HDR_SIZE || > + ubi->leb_start < ubi->vid_hdr_offset + UBI_VID_HDR_SIZE || > + ubi->leb_start > ubi->peb_size - UBI_VID_HDR_SIZE || > + ubi->leb_start & (ubi->min_io_size - 1)) { > + ubi_err("bad VID header (%d) or data offsets (%d)", > + ubi->vid_hdr_offset, ubi->leb_start); > + return -EINVAL; > + } > + > + /* > + * It may happen that EC and VID headers are situated in one minimal > + * I/O unit. In this case we can only accept this UBI image in > + * read-only mode. > + */ > + if (ubi->vid_hdr_offset + UBI_VID_HDR_SIZE <= ubi->hdrs_min_io_size) { > + ubi_warn("EC and VID headers are in the same minimal I/O > unit, " > + "switch to read-only mode"); > + ubi->ro_mode = 1; > + } > + > + ubi->leb_size = ubi->peb_size - ubi->leb_start; > + > + if (!(ubi->mtd->flags & MTD_WRITEABLE)) { > + ubi_msg("MTD device %d is write-protected, attach in " > + "read-only mode", ubi->mtd->index); > + ubi->ro_mode = 1; > + } > + > + ubi_msg("physical eraseblock size: %d bytes (%d KiB)", > + ubi->peb_size, ubi->peb_size >> 10); > + ubi_msg("logical eraseblock size: %d bytes", ubi->leb_size); > + ubi_msg("smallest flash I/O unit: %d", ubi->min_io_size); > + if (ubi->hdrs_min_io_size != ubi->min_io_size) > + ubi_msg("sub-page size: %d", > + ubi->hdrs_min_io_size); > + ubi_msg("VID header offset: %d (aligned %d)", > + ubi->vid_hdr_offset, ubi->vid_hdr_aloffset); > + ubi_msg("data offset: %d", ubi->leb_start); I got these messages on my console, my suggestion is that (almost) all of the standard info messages are off by default. > +int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) > +{ > + struct ubi_device *ubi; > + int i, err; > + > + /* > + * Check if we already have the same MTD device attached. > + * > + * Note, this function assumes that UBI devices creations and > deletions > + * are serialized, so it does not take the &ubi_devices_lock. > + */ > + for (i = 0; i < UBI_MAX_DEVICES; i++) { > + ubi = ubi_devices[i]; > + if (ubi && mtd->index == ubi->mtd->index) { > + dbg_err("mtd%d is already attached to ubi%d", > + mtd->index, i); > + return -EEXIST; > + } > + } > + > + /* > + * Make sure this MTD device is not emulated on top of an UBI volume > + * already. Well, generally this recursion works fine, but there are > + * different problems like the UBI module takes a reference to itself > + * by attaching (and thus, opening) the emulated MTD device. This > + * results in inability to unload the module. And in general it makes > + * no sense to attach emulated MTD devices, so we prohibit this. > + */ > + if (mtd->type == MTD_UBIVOLUME) { > + ubi_err("refuse attaching mtd%d - it is already emulated on " > + "top of UBI", mtd->index); > + return -EINVAL; > + } > + > + if (ubi_num == UBI_DEV_NUM_AUTO) { > + /* Search for an empty slot in the @ubi_devices array */ > + for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++) > + if (!ubi_devices[ubi_num]) > + break; > + if (ubi_num == UBI_MAX_DEVICES) { > + dbg_err("only %d UBI devices may be created", > UBI_MAX_DEVICES); > + return -ENFILE; > + } > + } else { > + if (ubi_num >= UBI_MAX_DEVICES) > + return -EINVAL; > + > + /* Make sure ubi_num is not busy */ > + if (ubi_devices[ubi_num]) { > + dbg_err("ubi%d already exists", ubi_num); > + return -EEXIST; > + } > + } > + > + ubi = kzalloc(sizeof(struct ubi_device), GFP_KERNEL); > + if (!ubi) > + return -ENOMEM; > + > + ubi->mtd = mtd; > + ubi->ubi_num = ubi_num; > + ubi->vid_hdr_offset = vid_hdr_offset; > + ubi->autoresize_vol_id = -1; > + > + mutex_init(&ubi->buf_mutex); > + mutex_init(&ubi->ckvol_mutex); > + mutex_init(&ubi->volumes_mutex); > + spin_lock_init(&ubi->volumes_lock); > + > + ubi_msg("attaching mtd%d to ubi%d", mtd->index, ubi_num); > + > + err = io_init(ubi); > + if (err) > + goto out_free; > + > + ubi->peb_buf1 = vmalloc(ubi->peb_size); > + if (!ubi->peb_buf1) > + goto out_free; > + > + ubi->peb_buf2 = vmalloc(ubi->peb_size); > + if (!ubi->peb_buf2) > + goto out_free; > + > +#ifdef CONFIG_MTD_UBI_DEBUG > + mutex_init(&ubi->dbg_buf_mutex); > + ubi->dbg_peb_buf = vmalloc(ubi->peb_size); > + if (!ubi->dbg_peb_buf) > + goto out_free; > +#endif > + > + err = attach_by_scanning(ubi); > + if (err) { > + dbg_err("failed to attach by scanning, error %d", err); > + goto out_free; > + } > + > + if (ubi->autoresize_vol_id != -1) { > + err = autoresize(ubi, ubi->autoresize_vol_id); > + if (err) > + goto out_detach; > + } > + > + err = uif_init(ubi); > + if (err) > + goto out_detach; > + > + ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name); > + if (IS_ERR(ubi->bgt_thread)) { > + err = PTR_ERR(ubi->bgt_thread); > + ubi_err("cannot spawn \"%s\", error %d", ubi->bgt_name, > + err); > + goto out_uif; > + } > + > + ubi_msg("attached mtd%d to ubi%d", mtd->index, ubi_num); > + ubi_msg("MTD device name: \"%s\"", mtd->name); > + ubi_msg("MTD device size: %llu MiB", ubi->flash_size >> > 20); > + ubi_msg("number of good PEBs: %d", ubi->good_peb_count); > + ubi_msg("number of bad PEBs: %d", ubi->bad_peb_count); > + ubi_msg("max. allowed volumes: %d", ubi->vtbl_slots); > + ubi_msg("wear-leveling threshold: %d", > CONFIG_MTD_UBI_WL_THRESHOLD); > + ubi_msg("number of internal volumes: %d", UBI_INT_VOL_COUNT); > + ubi_msg("number of user volumes: %d", > + ubi->vol_count - UBI_INT_VOL_COUNT); > + ubi_msg("available PEBs: %d", ubi->avail_pebs); > + ubi_msg("total number of reserved PEBs: %d", ubi->rsvd_pebs); > + 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); All these should also be off by default IMO. Regards, Magnus _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot