[U-Boot] [PATCH] Add MTD core & partition

It's preparation for UBI codes. UBI uses partition and get & put mtd devices
Signed-off-by: Kyungmin Park kyungmin.park@samsung.com --- diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 6538f7a..d225a68 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -25,6 +25,7 @@ include $(TOPDIR)/config.mk
LIB := $(obj)libmtd.a
+COBJS-$(CONFIG_CMD_UBI) += mtdcore.o mtdpart.o COBJS-$(CONFIG_HAS_DATAFLASH) += at45.o COBJS-$(CONFIG_FLASH_CFI_DRIVER) += cfi_flash.o COBJS-$(CONFIG_HAS_DATAFLASH) += dataflash.o diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c new file mode 100644 index 0000000..2fb6099 --- /dev/null +++ b/drivers/mtd/mtdcore.c @@ -0,0 +1,142 @@ +/* + * $Id: mtdcore.c,v 1.47 2005/11/07 11:14:20 gleixner Exp $ + * + * Core registration and callback routines for MTD + * drivers and users. + */ + +#include <linux/mtd/mtd.h> +#include <mtd_uboot.h> +#include <ubi_uboot.h> + +struct mtd_info *mtd_table[MAX_MTD_DEVICES]; + +int add_mtd_device(struct mtd_info *mtd) +{ + int i; + + BUG_ON(mtd->writesize == 0); + + for (i=0; i < MAX_MTD_DEVICES; i++) + if (!mtd_table[i]) { + mtd_table[i] = mtd; + mtd->index = i; + mtd->usecount = 0; + + printf("mtd: Giving out device %d to %s\n",i, mtd->name); + /* No need to get a refcount on the module containing + the notifier, since we hold the mtd_table_mutex */ + + /* We _know_ we aren't being removed, because + our caller is still holding us here. So none + of this try_ nonsense, and no bitching about it + either. :) */ + return 0; + } + + return 1; +} + +/** + * del_mtd_device - unregister an MTD device + * @mtd: pointer to MTD device info structure + * + * Remove a device from the list of MTD devices present in the system, + * and notify each currently active MTD 'user' of its departure. + * Returns zero on success or 1 on failure, which currently will happen + * if the requested device does not appear to be present in the list. + */ +int del_mtd_device (struct mtd_info *mtd) +{ + int ret; + + if (mtd_table[mtd->index] != mtd) { + ret = -ENODEV; + } else if (mtd->usecount) { + printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count %d\n", + mtd->index, mtd->name, mtd->usecount); + ret = -EBUSY; + } else { + /* No need to get a refcount on the module containing + * the notifier, since we hold the mtd_table_mutex */ + mtd_table[mtd->index] = NULL; + + ret = 0; + } + + return ret; +} + +/** + * get_mtd_device - obtain a validated handle for an MTD device + * @mtd: last known address of the required MTD device + * @num: internal device number of the required MTD device + * + * Given a number and NULL address, return the num'th entry in the device + * table, if any. Given an address and num == -1, search the device table + * for a device with that address and return if it's still present. Given + * both, return the num'th driver only if its address matches. Return + * error code if not. + */ +struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num) +{ + struct mtd_info *ret = NULL; + int i, err = -ENODEV; + + if (num == -1) { + for (i=0; i< MAX_MTD_DEVICES; i++) + if (mtd_table[i] == mtd) + ret = mtd_table[i]; + } else if (num < MAX_MTD_DEVICES) { + ret = mtd_table[num]; + if (mtd && mtd != ret) + ret = NULL; + } + + if (!ret) + goto out_unlock; + + ret->usecount++; + return ret; + +out_unlock: + return ERR_PTR(err); +} + +/** + * get_mtd_device_nm - obtain a validated handle for an MTD device by + * device name + * @name: MTD device name to open + * + * This function returns MTD device description structure in case of + * success and an error code in case of failure. + */ +struct mtd_info *get_mtd_device_nm(const char *name) +{ + int i, err = -ENODEV; + struct mtd_info *mtd = NULL; + + for (i = 0; i < MAX_MTD_DEVICES; i++) { + if (mtd_table[i] && !strcmp(name, mtd_table[i]->name)) { + mtd = mtd_table[i]; + break; + } + } + + if (!mtd) + goto out_unlock; + + mtd->usecount++; + return mtd; + +out_unlock: + return ERR_PTR(err); +} + +void put_mtd_device(struct mtd_info *mtd) +{ + int c; + + c = --mtd->usecount; + BUG_ON(c < 0); +} diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c new file mode 100644 index 0000000..113516a --- /dev/null +++ b/drivers/mtd/mtdpart.c @@ -0,0 +1,531 @@ +/* + * Simple MTD partitioning layer + * + * (C) 2000 Nicolas Pitre nico@cam.org + * + * This code is GPL + * + * $Id: mtdpart.c,v 1.55 2005/11/07 11:14:20 gleixner Exp $ + * + * 02-21-2002 Thomas Gleixner gleixner@autronix.de + * added support for read_oob, write_oob + */ + +#include <common.h> +#include <malloc.h> +#include <asm/errno.h> + +#include <linux/types.h> +#include <linux/list.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/compat.h> + +/* Our partition linked list */ +static LIST_HEAD(mtd_partitions); + +/* Our partition node structure */ +struct mtd_part { + struct mtd_info mtd; + struct mtd_info *master; + u_int32_t offset; + int index; + struct list_head list; + int registered; +}; + +/* + * Given a pointer to the MTD object in the mtd_part structure, we can retrieve + * the pointer to that structure with this macro. + */ +#define PART(x) ((struct mtd_part *)(x)) + + +/* + * MTD methods which simply translate the effective address and pass through + * to the _real_ device. + */ + +static int part_read (struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct mtd_part *part = PART(mtd); + int res; + + if (from >= mtd->size) + len = 0; + else if (from + len > mtd->size) + len = mtd->size - from; + res = part->master->read (part->master, from + part->offset, + len, retlen, buf); +#if 0 + if (unlikely(res)) { + if (res == -EUCLEAN) + mtd->ecc_stats.corrected++; + if (res == -EBADMSG) + mtd->ecc_stats.failed++; + } +#endif + return res; +} + +#if 0 +static int part_point (struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, void **virt, resource_size_t *phys) +{ + struct mtd_part *part = PART(mtd); + if (from >= mtd->size) + len = 0; + else if (from + len > mtd->size) + len = mtd->size - from; + return part->master->point (part->master, from + part->offset, + len, retlen, virt, phys); +} + +static void part_unpoint(struct mtd_info *mtd, loff_t from, size_t len) +{ + struct mtd_part *part = PART(mtd); + + part->master->unpoint(part->master, from + part->offset, len); +} + +static int part_read_oob(struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *ops) +{ + struct mtd_part *part = PART(mtd); + int res; + + if (from >= mtd->size) + return -EINVAL; + if (ops->datbuf && from + ops->len > mtd->size) + return -EINVAL; + res = part->master->read_oob(part->master, from + part->offset, ops); + + if (unlikely(res)) { + if (res == -EUCLEAN) + mtd->ecc_stats.corrected++; + if (res == -EBADMSG) + mtd->ecc_stats.failed++; + } + return res; +} + +static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct mtd_part *part = PART(mtd); + return part->master->read_user_prot_reg (part->master, from, + len, retlen, buf); +} + +static int part_get_user_prot_info (struct mtd_info *mtd, + struct otp_info *buf, size_t len) +{ + struct mtd_part *part = PART(mtd); + return part->master->get_user_prot_info (part->master, buf, len); +} + +static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct mtd_part *part = PART(mtd); + return part->master->read_fact_prot_reg (part->master, from, + len, retlen, buf); +} + +static int part_get_fact_prot_info (struct mtd_info *mtd, + struct otp_info *buf, size_t len) +{ + struct mtd_part *part = PART(mtd); + return part->master->get_fact_prot_info (part->master, buf, len); +} +#endif + +static int part_write (struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct mtd_part *part = PART(mtd); + if (!(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + if (to >= mtd->size) + len = 0; + else if (to + len > mtd->size) + len = mtd->size - to; + return part->master->write (part->master, to + part->offset, + len, retlen, buf); +} + +#if 0 +static int part_panic_write (struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct mtd_part *part = PART(mtd); + if (!(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + if (to >= mtd->size) + len = 0; + else if (to + len > mtd->size) + len = mtd->size - to; + return part->master->panic_write (part->master, to + part->offset, + len, retlen, buf); +} + +static int part_write_oob(struct mtd_info *mtd, loff_t to, + struct mtd_oob_ops *ops) +{ + struct mtd_part *part = PART(mtd); + + if (!(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + + if (to >= mtd->size) + return -EINVAL; + if (ops->datbuf && to + ops->len > mtd->size) + return -EINVAL; + return part->master->write_oob(part->master, to + part->offset, ops); +} + +static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct mtd_part *part = PART(mtd); + return part->master->write_user_prot_reg (part->master, from, + len, retlen, buf); +} + +static int part_lock_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len) +{ + struct mtd_part *part = PART(mtd); + return part->master->lock_user_prot_reg (part->master, from, len); +} + +static int part_writev (struct mtd_info *mtd, const struct kvec *vecs, + unsigned long count, loff_t to, size_t *retlen) +{ + struct mtd_part *part = PART(mtd); + if (!(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + return part->master->writev (part->master, vecs, count, + to + part->offset, retlen); +} +#endif + +static int part_erase (struct mtd_info *mtd, struct erase_info *instr) +{ + struct mtd_part *part = PART(mtd); + int ret; + if (!(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + if (instr->addr >= mtd->size) + return -EINVAL; + instr->addr += part->offset; + ret = part->master->erase(part->master, instr); + if (ret) { + if (instr->fail_addr != 0xffffffff) + instr->fail_addr -= part->offset; + instr->addr -= part->offset; + } + return ret; +} + +void mtd_erase_callback(struct erase_info *instr) +{ + if (instr->mtd->erase == part_erase) { + struct mtd_part *part = PART(instr->mtd); + + if (instr->fail_addr != 0xffffffff) + instr->fail_addr -= part->offset; + instr->addr -= part->offset; + } + if (instr->callback) + instr->callback(instr); +} +#if 0 +EXPORT_SYMBOL_GPL(mtd_erase_callback); +#endif + +#if 0 +static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len) +{ + struct mtd_part *part = PART(mtd); + if ((len + ofs) > mtd->size) + return -EINVAL; + return part->master->lock(part->master, ofs + part->offset, len); +} + +static int part_unlock (struct mtd_info *mtd, loff_t ofs, size_t len) +{ + struct mtd_part *part = PART(mtd); + if ((len + ofs) > mtd->size) + return -EINVAL; + return part->master->unlock(part->master, ofs + part->offset, len); +} +#endif + +static void part_sync(struct mtd_info *mtd) +{ + struct mtd_part *part = PART(mtd); + part->master->sync(part->master); +} + +#if 0 +static int part_suspend(struct mtd_info *mtd) +{ + struct mtd_part *part = PART(mtd); + return part->master->suspend(part->master); +} + +static void part_resume(struct mtd_info *mtd) +{ + struct mtd_part *part = PART(mtd); + part->master->resume(part->master); +} +#endif + +static int part_block_isbad (struct mtd_info *mtd, loff_t ofs) +{ + struct mtd_part *part = PART(mtd); + if (ofs >= mtd->size) + return -EINVAL; + ofs += part->offset; + return part->master->block_isbad(part->master, ofs); +} + +static int part_block_markbad (struct mtd_info *mtd, loff_t ofs) +{ + struct mtd_part *part = PART(mtd); + int res; + + if (!(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + if (ofs >= mtd->size) + return -EINVAL; + ofs += part->offset; + res = part->master->block_markbad(part->master, ofs); +#if 0 + if (!res) + mtd->ecc_stats.badblocks++; +#endif + return res; +} + +/* + * This function unregisters and destroy all slave MTD objects which are + * attached to the given master MTD object. + */ + +int del_mtd_partitions(struct mtd_info *master) +{ + struct list_head *node; + struct mtd_part *slave; + + for (node = mtd_partitions.next; + node != &mtd_partitions; + node = node->next) { + slave = list_entry(node, struct mtd_part, list); + if (slave->master == master) { + struct list_head *prev = node->prev; + __list_del(prev, node->next); + if(slave->registered) + del_mtd_device(&slave->mtd); + kfree(slave); + node = prev; + } + } + + return 0; +} + +/* + * This function, given a master MTD object and a partition table, creates + * and registers slave MTD objects which are bound to the master according to + * the partition definitions. + * (Q: should we register the master MTD object as well?) + */ + +int add_mtd_partitions(struct mtd_info *master, + const struct mtd_partition *parts, + int nbparts) +{ + struct mtd_part *slave; + u_int32_t cur_offset = 0; + int i; + + printk (KERN_NOTICE "Creating %d MTD partitions on "%s":\n", nbparts, master->name); + + for (i = 0; i < nbparts; i++) { + + /* allocate the partition structure */ + slave = kzalloc (sizeof(*slave), GFP_KERNEL); + if (!slave) { + printk ("memory allocation error while creating partitions for "%s"\n", + master->name); + del_mtd_partitions(master); + return -ENOMEM; + } + list_add(&slave->list, &mtd_partitions); + + /* set up the MTD object for this partition */ + slave->mtd.type = master->type; + slave->mtd.flags = master->flags & ~parts[i].mask_flags; + slave->mtd.size = parts[i].size; + slave->mtd.writesize = master->writesize; + slave->mtd.oobsize = master->oobsize; + slave->mtd.oobavail = master->oobavail; + slave->mtd.subpage_sft = master->subpage_sft; + + slave->mtd.name = parts[i].name; + slave->mtd.owner = master->owner; + + slave->mtd.read = part_read; + slave->mtd.write = part_write; + +#if 0 + if (master->panic_write) + slave->mtd.panic_write = part_panic_write; + + if(master->point && master->unpoint){ + slave->mtd.point = part_point; + slave->mtd.unpoint = part_unpoint; + } + + if (master->read_oob) + slave->mtd.read_oob = part_read_oob; + if (master->write_oob) + slave->mtd.write_oob = part_write_oob; + if(master->read_user_prot_reg) + slave->mtd.read_user_prot_reg = part_read_user_prot_reg; + if(master->read_fact_prot_reg) + slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg; + if(master->write_user_prot_reg) + slave->mtd.write_user_prot_reg = part_write_user_prot_reg; + if(master->lock_user_prot_reg) + slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg; + if(master->get_user_prot_info) + slave->mtd.get_user_prot_info = part_get_user_prot_info; + if(master->get_fact_prot_info) + slave->mtd.get_fact_prot_info = part_get_fact_prot_info; +#endif + if (master->sync) + slave->mtd.sync = part_sync; +#if 0 + if (!i && master->suspend && master->resume) { + slave->mtd.suspend = part_suspend; + slave->mtd.resume = part_resume; + } + if (master->writev) + slave->mtd.writev = part_writev; + if (master->lock) + slave->mtd.lock = part_lock; + if (master->unlock) + slave->mtd.unlock = part_unlock; +#endif + if (master->block_isbad) + slave->mtd.block_isbad = part_block_isbad; + if (master->block_markbad) + slave->mtd.block_markbad = part_block_markbad; + slave->mtd.erase = part_erase; + slave->master = master; + slave->offset = parts[i].offset; + slave->index = i; + + if (slave->offset == MTDPART_OFS_APPEND) + slave->offset = cur_offset; + if (slave->offset == MTDPART_OFS_NXTBLK) { + slave->offset = cur_offset; + if ((cur_offset % master->erasesize) != 0) { + /* Round up to next erasesize */ + slave->offset = ((cur_offset / master->erasesize) + 1) * master->erasesize; + printk(KERN_NOTICE "Moving partition %d: " + "0x%08x -> 0x%08x\n", i, + cur_offset, slave->offset); + } + } + if (slave->mtd.size == MTDPART_SIZ_FULL) + slave->mtd.size = master->size - slave->offset; + cur_offset = slave->offset + slave->mtd.size; + + printk (KERN_NOTICE "0x%08x-0x%08x : "%s"\n", slave->offset, + slave->offset + slave->mtd.size, slave->mtd.name); + + /* let's do some sanity checks */ + if (slave->offset >= master->size) { + /* let's register it anyway to preserve ordering */ + slave->offset = 0; + slave->mtd.size = 0; + printk ("mtd: partition "%s" is out of reach -- disabled\n", + parts[i].name); + } + if (slave->offset + slave->mtd.size > master->size) { + slave->mtd.size = master->size - slave->offset; + printk ("mtd: partition "%s" extends beyond the end of device "%s" -- size truncated to %#x\n", + parts[i].name, master->name, slave->mtd.size); + } + if (master->numeraseregions>1) { + /* Deal with variable erase size stuff */ + int i; + struct mtd_erase_region_info *regions = master->eraseregions; + + /* Find the first erase regions which is part of this partition. */ + for (i=0; i < master->numeraseregions && slave->offset >= regions[i].offset; i++) + ; + + for (i--; i < master->numeraseregions && slave->offset + slave->mtd.size > regions[i].offset; i++) { + if (slave->mtd.erasesize < regions[i].erasesize) { + slave->mtd.erasesize = regions[i].erasesize; + } + } + } else { + /* Single erase size */ + slave->mtd.erasesize = master->erasesize; + } + + if ((slave->mtd.flags & MTD_WRITEABLE) && + (slave->offset % slave->mtd.erasesize)) { + /* Doesn't start on a boundary of major erase size */ + /* FIXME: Let it be writable if it is on a boundary of _minor_ erase size though */ + slave->mtd.flags &= ~MTD_WRITEABLE; + printk ("mtd: partition "%s" doesn't start on an erase block boundary -- force read-only\n", + parts[i].name); + } + if ((slave->mtd.flags & MTD_WRITEABLE) && + (slave->mtd.size % slave->mtd.erasesize)) { + slave->mtd.flags &= ~MTD_WRITEABLE; + printk ("mtd: partition "%s" doesn't end on an erase block -- force read-only\n", + parts[i].name); + } + +#if 0 + slave->mtd.ecclayout = master->ecclayout; + if (master->block_isbad) { + uint32_t offs = 0; + + while(offs < slave->mtd.size) { + if (master->block_isbad(master, + offs + slave->offset)) + slave->mtd.ecc_stats.badblocks++; + offs += slave->mtd.erasesize; + } + } + + if(parts[i].mtdp) + { /* store the object pointer (caller may or may not register it */ + *parts[i].mtdp = &slave->mtd; + slave->registered = 0; + } + else +#endif + { + /* register our partition */ + add_mtd_device(&slave->mtd); + slave->registered = 1; + } + } + + return 0; +} + +#if 0 +EXPORT_SYMBOL(add_mtd_partitions); +EXPORT_SYMBOL(del_mtd_partitions); +#endif

Dear Kyungmin Park,
In message 20080829081323.GA4269@july you wrote:
It's preparation for UBI codes. UBI uses partition and get & put mtd devices
Please co-ordinate any UBI-related work with Stefan Roese.
I will not apply any UBI related patches unless I have his ACK.
Best regards,
Wolfgang Denk

Dear Wolfgang,
In message 20080829081323.GA4269@july you wrote:
It's preparation for UBI codes. UBI uses partition and get & put mtd devices
Please co-ordinate any UBI-related work with Stefan Roese.
I will not apply any UBI related patches unless I have his ACK.
Sure, I agreed your opinions. Then how about to crate u-boot-ubi tree for others?
Now we are using UBI both NAND and OneNAND. To do this, we also change OneNAND command to support UBI fully. but previous patch it doesn't have.
I want to share our works at least UBI.
If you have more opinions please let me know.
Thank you, Kyungmin Park

Kyungmi,
On Monday 08 September 2008, Kyungmin Park wrote:
It's preparation for UBI codes. UBI uses partition and get & put mtd devices
Please co-ordinate any UBI-related work with Stefan Roese.
I will not apply any UBI related patches unless I have his ACK.
I have no objections to this patch. So here my:
Acked-by: Stefan Roese sr@denx.de
But I think it would be a good idea if Scott Wood could also take a look at this patch (and the whole UBI integration) since this UBI integration also touches "his" NAND infrastructure.
Scott, any comments?
Sure, I agreed your opinions. Then how about to crate u-boot-ubi tree for others?
Good idea. Please see below.
Now we are using UBI both NAND and OneNAND. To do this, we also change OneNAND command to support UBI fully. but previous patch it doesn't have.
I want to share our works at least UBI.
We really appreciate this. Thanks a lot.
If you have more opinions please let me know.
We will add an new u-boot-ubi repository and would like you to become the custodian. Would you accept this? Do you (or anybody else) have other volunteers for this job?
If you accept this and nobody objects, please send your public SSH key to Wolfgang in a private mail, so that he can create the new repository for you.
Thanks.
Best regards, Stefan
===================================================================== DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: +49-8142-66989-0 Fax: +49-8142-66989-80 Email: office@denx.de =====================================================================

On Fri, Aug 29, 2008 at 05:13:23PM +0900, Kyungmin Park wrote:
It's preparation for UBI codes. UBI uses partition and get & put mtd devices
Please import the latest MTD code; there have been several cleanups/fixes in mtdpart.c recently (in particular, the patches from Atsushi Nemoto dated Jul 19).
As for the #if 0 blocks, I'd rather leave them out entirely -- I think the increased readability would be worth the occasional extra merge conflict when importing new upstream code.
Signed-off-by: Kyungmin Park kyungmin.park@samsung.com
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 6538f7a..d225a68 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -25,6 +25,7 @@ include $(TOPDIR)/config.mk
LIB := $(obj)libmtd.a
+COBJS-$(CONFIG_CMD_UBI) += mtdcore.o mtdpart.o
Is UBI the only case where we want the generic MTD infrastructure? Maybe we can remove some duplication and/or add partition support elsewhere.
COBJS-$(CONFIG_HAS_DATAFLASH) += at45.o COBJS-$(CONFIG_FLASH_CFI_DRIVER) += cfi_flash.o COBJS-$(CONFIG_HAS_DATAFLASH) += dataflash.o diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c new file mode 100644 index 0000000..2fb6099 --- /dev/null +++ b/drivers/mtd/mtdcore.c @@ -0,0 +1,142 @@ +/*
- $Id: mtdcore.c,v 1.47 2005/11/07 11:14:20 gleixner Exp $
- Core registration and callback routines for MTD
- drivers and users.
- */
+#include <linux/mtd/mtd.h> +#include <mtd_uboot.h> +#include <ubi_uboot.h>
I don't see mtd_uboot.h or ubi_uboot.h in the current tree, nor are they added by this patch.
Is this patch supposed to depend on the giant UBI patch (I'd think not, since the changelog says it's preparing for UBI)?
+/**
del_mtd_device - unregister an MTD device
@mtd: pointer to MTD device info structure
Remove a device from the list of MTD devices present in the system,
and notify each currently active MTD 'user' of its departure.
Returns zero on success or 1 on failure, which currently will happen
if the requested device does not appear to be present in the list.
- */
+int del_mtd_device (struct mtd_info *mtd) +{
- int ret;
- if (mtd_table[mtd->index] != mtd) {
ret = -ENODEV;
- } else if (mtd->usecount) {
printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count %d\n",
mtd->index, mtd->name, mtd->usecount);
ret = -EBUSY;
- } else {
/* No need to get a refcount on the module containing
* the notifier, since we hold the mtd_table_mutex */
mtd_table[mtd->index] = NULL;
ret = 0;
- }
- return ret;
+}
We should remove all the refcounting/removal stuff -- it's just bloat in u-boot.
-Scott

On Tue, Sep 9, 2008 at 4:30 AM, Scott Wood scottwood@freescale.com wrote:
On Fri, Aug 29, 2008 at 05:13:23PM +0900, Kyungmin Park wrote:
It's preparation for UBI codes. UBI uses partition and get & put mtd devices
Please import the latest MTD code; there have been several cleanups/fixes in mtdpart.c recently (in particular, the patches from Atsushi Nemoto dated Jul 19).
As for the #if 0 blocks, I'd rather leave them out entirely -- I think the increased readability would be worth the occasional extra merge conflict when importing new upstream code.
That's the reason I want to create new tree to sync u-boot tree. At that time there's no point, ecc_stats, and ... fields at mtd_info, So I disable it. Now it's included and we can remove #if 0.
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 6538f7a..d225a68 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -25,6 +25,7 @@ include $(TOPDIR)/config.mk
LIB := $(obj)libmtd.a
+COBJS-$(CONFIG_CMD_UBI) += mtdcore.o mtdpart.o
Is UBI the only case where we want the generic MTD infrastructure? Maybe we can remove some duplication and/or add partition support elsewhere.
Yes I agree. As I know there's no users to use mtdpart. Instead it used another mtdpart format at mtdpart command. Next time it changes from previous one to MTD infrastructure.
COBJS-$(CONFIG_HAS_DATAFLASH) += at45.o COBJS-$(CONFIG_FLASH_CFI_DRIVER) += cfi_flash.o COBJS-$(CONFIG_HAS_DATAFLASH) += dataflash.o diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c new file mode 100644 index 0000000..2fb6099 --- /dev/null +++ b/drivers/mtd/mtdcore.c @@ -0,0 +1,142 @@ +/*
- $Id: mtdcore.c,v 1.47 2005/11/07 11:14:20 gleixner Exp $
- Core registration and callback routines for MTD
- drivers and users.
- */
+#include <linux/mtd/mtd.h> +#include <mtd_uboot.h> +#include <ubi_uboot.h>
I don't see mtd_uboot.h or ubi_uboot.h in the current tree, nor are they added by this patch.
Is this patch supposed to depend on the giant UBI patch (I'd think not, since the changelog says it's preparing for UBI)?
+/**
del_mtd_device - unregister an MTD device
@mtd: pointer to MTD device info structure
Remove a device from the list of MTD devices present in the system,
and notify each currently active MTD 'user' of its departure.
Returns zero on success or 1 on failure, which currently will happen
if the requested device does not appear to be present in the list.
- */
+int del_mtd_device (struct mtd_info *mtd) +{
int ret;
if (mtd_table[mtd->index] != mtd) {
ret = -ENODEV;
} else if (mtd->usecount) {
printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count %d\n",
mtd->index, mtd->name, mtd->usecount);
ret = -EBUSY;
} else {
/* No need to get a refcount on the module containing
* the notifier, since we hold the mtd_table_mutex */
mtd_table[mtd->index] = NULL;
ret = 0;
}
return ret;
+}
We should remove all the refcounting/removal stuff -- it's just bloat in u-boot.
I don't want to remove or modify imported codes at least MTD & UBI codes.
Thank you, Kyungmin Park

Kyungmin Park <kmpark <at> infradead.org> writes:
It's preparation for UBI codes. UBI uses partition and get & put mtd devices
...
Hi,
how far have you got? We are planning to integrate UBI in u-boot too (NOR flashes), so if all is already done - or will be in next time - we could spare some hours ...
Kind Regards, Michael

On Friday 19 September 2008, Michael Lawnick wrote:
how far have you got? We are planning to integrate UBI in u-boot too (NOR flashes), so if all is already done - or will be in next time - we could spare some hours ...
We also have a project to integrate UBI support into U-Boot. The real UBI work will start in 2-3 weeks. We really should coordinate our work on this.
BTW: Which NOR FLASH driver are you using? The common CFI driver? It has no real connection to the MTD layer which is needed for the UBI port from Kyungmin. Did you think about this?
Thanks.
Best regards, Stefan
===================================================================== DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: +49-8142-66989-0 Fax: +49-8142-66989-80 Email: office@denx.de =====================================================================

Stefan Roese <sr <at> denx.de> writes:
On Friday 19 September 2008, Michael Lawnick wrote:
how far have you got? We are planning to integrate UBI in u-boot too (NOR flashes), so if all is already done - or will be in next time - we could spare some hours ...
We also have a project to integrate UBI support into U-Boot. The real UBI work will start in 2-3 weeks. We really should coordinate our work on this.
BTW: Which NOR FLASH driver are you using? The common CFI driver? It has no real connection to the MTD layer which is needed for the UBI port from Kyungmin. Did you think about this?
We are using CFI driver for AM29GL512. As said we are _planning_ to integrate, i.e. I'm currently gathering information. We need r/o access from u-boot to find our kernel and boot it. Writing to flash could be done from Linux. What are the problems to face?
Kind Regards, Michael

On Friday 19 September 2008, Michael Lawnick wrote:
BTW: Which NOR FLASH driver are you using? The common CFI driver? It has no real connection to the MTD layer which is needed for the UBI port from Kyungmin. Did you think about this?
We are using CFI driver for AM29GL512. As said we are _planning_ to integrate, i.e. I'm currently gathering information. We need r/o access from u-boot to find our kernel and boot it. Writing to flash could be done from Linux.
Understood.
What are the problems to face?
As I mentioned the CFI driver is missing the interface to the MTD layer. This is available for NAND and OneNAND but missing for NOR in the U-Boot CFI implementation. It really is not needed right now and such an extension has to be made carefully since it adds new code which increases the image size of all boards using this driver. The only option (I can think of) to not increase the image size for those boards would be to add this MTD connection via #ifdef's. But this will not help to make the code more readable. :-(
Best regards, Stefan
===================================================================== DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: +49-8142-66989-0 Fax: +49-8142-66989-80 Email: office@denx.de =====================================================================

Stefan Roese <sr <at> denx.de> writes:
On Friday 19 September 2008, Michael Lawnick wrote:
BTW: Which NOR FLASH driver are you using? The common CFI driver? It has no real connection to the MTD layer which is needed for the UBI port from Kyungmin. Did you think about this?
We are using CFI driver for AM29GL512. As said we are _planning_ to integrate, i.e. I'm currently gathering information. We need r/o access from u-boot to find our kernel and boot it. Writing to flash could be done from Linux.
Understood.
What are the problems to face?
As I mentioned the CFI driver is missing the interface to the MTD layer. This is available for NAND and OneNAND but missing for NOR in the U-Boot CFI implementation. It really is not needed right now and such an extension has to be made carefully since it adds new code which increases the image size of all boards using this driver. The only option (I can think of) to not increase the image size for those boards would be to add this MTD connection via #ifdef's. But this will not help to make the code more readable.
Hmm, seems I've got some problems to understand. If there is a clearly defined API (which I haven't found yet) it should be independent from H/W (NAND/NOR/SRAM/...) IMHO. If not, UBI will be NAND-only :-( Could you give me a kick into the right direction, so I will find e.g. a .h file where the functions are listed that have to be supported by H/W-layer driver?
#ifdef's could be avoided by using a different sort of driver for the same H/W, e.g. cfi_flash and cfi_ubi_flash.
Kind regards, Michael
participants (5)
-
Kyungmin Park
-
Michael Lawnick
-
Scott Wood
-
Stefan Roese
-
Wolfgang Denk