diff options
-rw-r--r-- | drivers/mtd/onenand/onenand_base.c | 24 | ||||
-rw-r--r-- | include/linux/mtd/onenand.h | 5 |
2 files changed, 22 insertions, 7 deletions
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 6d4e67f6c29..9e14a26ca4e 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -836,7 +836,7 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int col int readcol = column; int readend = column + thislen; int lastgap = 0; - uint8_t *oob_buf = this->page_buf + mtd->writesize; + uint8_t *oob_buf = this->oob_buf; for (free = this->ecclayout->oobfree; free->length; ++free) { if (readcol >= lastgap) @@ -1356,7 +1356,7 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, /* Grab the lock and see if the device is available */ onenand_get_device(mtd, FL_WRITING); - oobbuf = this->page_buf + mtd->writesize; + oobbuf = this->oob_buf; /* Loop until all data write */ while (written < len) { @@ -2332,15 +2332,25 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) /* Allocate buffers, if necessary */ if (!this->page_buf) { - size_t len; - len = mtd->writesize + mtd->oobsize; - this->page_buf = kmalloc(len, GFP_KERNEL); + this->page_buf = kzalloc(mtd->writesize, GFP_KERNEL); if (!this->page_buf) { printk(KERN_ERR "onenand_scan(): Can't allocate page_buf\n"); return -ENOMEM; } this->options |= ONENAND_PAGEBUF_ALLOC; } + if (!this->oob_buf) { + this->oob_buf = kzalloc(mtd->oobsize, GFP_KERNEL); + if (!this->oob_buf) { + printk(KERN_ERR "onenand_scan(): Can't allocate oob_buf\n"); + if (this->options & ONENAND_PAGEBUF_ALLOC) { + this->options &= ~ONENAND_PAGEBUF_ALLOC; + kfree(this->page_buf); + } + return -ENOMEM; + } + this->options |= ONENAND_OOBBUF_ALLOC; + } this->state = FL_READY; init_waitqueue_head(&this->wq); @@ -2437,9 +2447,11 @@ void onenand_release(struct mtd_info *mtd) kfree(bbm->bbt); kfree(this->bbm); } - /* Buffer allocated by onenand_scan */ + /* Buffers allocated by onenand_scan */ if (this->options & ONENAND_PAGEBUF_ALLOC) kfree(this->page_buf); + if (this->options & ONENAND_OOBBUF_ALLOC) + kfree(this->oob_buf); } EXPORT_SYMBOL_GPL(onenand_scan); diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h index d8af8a95e58..a56d24ada50 100644 --- a/include/linux/mtd/onenand.h +++ b/include/linux/mtd/onenand.h @@ -82,7 +82,8 @@ struct onenand_bufferram { * @wq: [INTERN] wait queue to sleep on if a OneNAND * operation is in progress * @state: [INTERN] the current state of the OneNAND device - * @page_buf: data buffer + * @page_buf: [INTERN] page main data buffer + * @oob_buf: [INTERN] page oob data buffer * @subpagesize: [INTERN] holds the subpagesize * @ecclayout: [REPLACEABLE] the default ecc placement scheme * @bbm: [REPLACEABLE] pointer to Bad Block Management @@ -122,6 +123,7 @@ struct onenand_chip { wait_queue_head_t wq; onenand_state_t state; unsigned char *page_buf; + unsigned char *oob_buf; int subpagesize; struct nand_ecclayout *ecclayout; @@ -156,6 +158,7 @@ struct onenand_chip { #define ONENAND_HAS_CONT_LOCK (0x0001) #define ONENAND_HAS_UNLOCK_ALL (0x0002) #define ONENAND_PAGEBUF_ALLOC (0x1000) +#define ONENAND_OOBBUF_ALLOC (0x2000) /* * OneNAND Flash Manufacturer ID Codes |