📄 onenand_base.c
字号:
if (this->bufferram[i].block == block && this->bufferram[i].page == page && this->bufferram[i].valid) return 1; return 0;}/** * onenand_update_bufferram - [GENERIC] Update BufferRAM information * @param mtd MTD data structure * @param addr address to update * @param valid valid flag * * Update BufferRAM information */static int onenand_update_bufferram(struct mtd_info *mtd, loff_t addr, int valid){ struct onenand_chip *this = mtd->priv; int block, page; int i; block = (int) (addr >> this->erase_shift); page = (int) (addr >> this->page_shift); page &= this->page_mask; /* Invalidate BufferRAM */ for (i = 0; i < MAX_BUFFERRAM; i++) { if (this->bufferram[i].block == block && this->bufferram[i].page == page) this->bufferram[i].valid = 0; } /* Update BufferRAM */ i = ONENAND_CURRENT_BUFFERRAM(this); this->bufferram[i].block = block; this->bufferram[i].page = page; this->bufferram[i].valid = valid; return 0;}/** * onenand_get_device - [GENERIC] Get chip for selected access * @param mtd MTD device structure * @param new_state the state which is requested * * Get the device and lock it for exclusive access */static int onenand_get_device(struct mtd_info *mtd, int new_state){ struct onenand_chip *this = mtd->priv; DECLARE_WAITQUEUE(wait, current); /* * Grab the lock and see if the device is available */ while (1) { spin_lock(&this->chip_lock); if (this->state == FL_READY) { this->state = new_state; spin_unlock(&this->chip_lock); break; } if (new_state == FL_PM_SUSPENDED) { spin_unlock(&this->chip_lock); return (this->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN; } set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&this->wq, &wait); spin_unlock(&this->chip_lock); schedule(); remove_wait_queue(&this->wq, &wait); } return 0;}/** * onenand_release_device - [GENERIC] release chip * @param mtd MTD device structure * * Deselect, release chip lock and wake up anyone waiting on the device */static void onenand_release_device(struct mtd_info *mtd){ struct onenand_chip *this = mtd->priv; /* Release the chip */ spin_lock(&this->chip_lock); this->state = FL_READY; wake_up(&this->wq); spin_unlock(&this->chip_lock);}/** * onenand_read_ecc - [MTD Interface] Read data with ECC * @param mtd MTD device structure * @param from offset to read from * @param len number of bytes to read * @param retlen pointer to variable to store the number of read bytes * @param buf the databuffer to put data * @param oob_buf filesystem supplied oob data buffer * @param oobsel oob selection structure * * OneNAND read with ECC */static int onenand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *oob_buf, struct nand_oobinfo *oobsel){ struct onenand_chip *this = mtd->priv; int read = 0, column; int thislen; int ret = 0; DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); /* Do not allow reads past end of device */ if ((from + len) > mtd->size) { DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_ecc: Attempt read beyond end of device\n"); *retlen = 0; return -EINVAL; } /* Grab the lock and see if the device is available */ onenand_get_device(mtd, FL_READING); /* TODO handling oob */ while (read < len) { thislen = min_t(int, mtd->oobblock, len - read); column = from & (mtd->oobblock - 1); if (column + thislen > mtd->oobblock) thislen = mtd->oobblock - column; if (!onenand_check_bufferram(mtd, from)) { this->command(mtd, ONENAND_CMD_READ, from, mtd->oobblock); ret = this->wait(mtd, FL_READING); /* First copy data and check return value for ECC handling */ onenand_update_bufferram(mtd, from, 1); } this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen); read += thislen; if (read == len) break; if (ret) { DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_ecc: read failed = %d\n", ret); goto out; } from += thislen; buf += thislen; }out: /* Deselect and wake up anyone waiting on the device */ onenand_release_device(mtd); /* * Return success, if no ECC failures, else -EBADMSG * fs driver will take care of that, because * retlen == desired len and result == -EBADMSG */ *retlen = read; return ret;}/** * onenand_read - [MTD Interface] MTD compability function for onenand_read_ecc * @param mtd MTD device structure * @param from offset to read from * @param len number of bytes to read * @param retlen pointer to variable to store the number of read bytes * @param buf the databuffer to put data * * This function simply calls onenand_read_ecc with oob buffer and oobsel = NULL*/static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf){ return onenand_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);}/** * onenand_read_oob - [MTD Interface] OneNAND read out-of-band * @param mtd MTD device structure * @param from offset to read from * @param len number of bytes to read * @param retlen pointer to variable to store the number of read bytes * @param buf the databuffer to put data * * OneNAND read out-of-band data from the spare area */static int onenand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf){ struct onenand_chip *this = mtd->priv; int read = 0, thislen, column; int ret = 0; DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); /* Initialize return length value */ *retlen = 0; /* Do not allow reads past end of device */ if (unlikely((from + len) > mtd->size)) { DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: Attempt read beyond end of device\n"); return -EINVAL; } /* Grab the lock and see if the device is available */ onenand_get_device(mtd, FL_READING); column = from & (mtd->oobsize - 1); while (read < len) { thislen = mtd->oobsize - column; thislen = min_t(int, thislen, len); this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize); onenand_update_bufferram(mtd, from, 0); ret = this->wait(mtd, FL_READING); /* First copy data and check return value for ECC handling */ this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); read += thislen; if (read == len) break; if (ret) { DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: read failed = %d\n", ret); goto out; } buf += thislen; /* Read more? */ if (read < len) { /* Page size */ from += mtd->oobblock; column = 0; } }out: /* Deselect and wake up anyone waiting on the device */ onenand_release_device(mtd); *retlen = read; return ret;}#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE/** * onenand_verify_oob - [GENERIC] verify the oob contents after a write * @param mtd MTD device structure * @param buf the databuffer to verify * @param to offset to read from * @param len number of bytes to read and compare * */static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to, int len){ struct onenand_chip *this = mtd->priv; char *readp = this->page_buf; int column = to & (mtd->oobsize - 1); int status, i; this->command(mtd, ONENAND_CMD_READOOB, to, mtd->oobsize); onenand_update_bufferram(mtd, to, 0); status = this->wait(mtd, FL_READING); if (status) return status; this->read_bufferram(mtd, ONENAND_SPARERAM, readp, column, len); for(i = 0; i < len; i++) if (buf[i] != 0xFF && buf[i] != readp[i]) return -EBADMSG; return 0;}/** * onenand_verify_page - [GENERIC] verify the chip contents after a write * @param mtd MTD device structure * @param buf the databuffer to verify * * Check DataRAM area directly */static int onenand_verify_page(struct mtd_info *mtd, u_char *buf, loff_t addr){ struct onenand_chip *this = mtd->priv; void __iomem *dataram0, *dataram1; int ret = 0; this->command(mtd, ONENAND_CMD_READ, addr, mtd->oobblock); ret = this->wait(mtd, FL_READING); if (ret) return ret; onenand_update_bufferram(mtd, addr, 1); /* Check, if the two dataram areas are same */ dataram0 = this->base + ONENAND_DATARAM; dataram1 = dataram0 + mtd->oobblock; if (memcmp(dataram0, dataram1, mtd->oobblock)) return -EBADMSG; return 0;}#else#define onenand_verify_page(...) (0)#define onenand_verify_oob(...) (0)#endif#define NOTALIGNED(x) ((x & (mtd->oobblock - 1)) != 0)/** * onenand_write_ecc - [MTD Interface] OneNAND write with ECC * @param mtd MTD device structure * @param to offset to write to * @param len number of bytes to write * @param retlen pointer to variable to store the number of written bytes * @param buf the data to write * @param eccbuf filesystem supplied oob data buffer * @param oobsel oob selection structure * * OneNAND write with ECC */static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel){ struct onenand_chip *this = mtd->priv; int written = 0; int ret = 0; DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); /* Initialize retlen, in case of early exit */ *retlen = 0; /* Do not allow writes past end of device */ if (unlikely((to + len) > mtd->size)) { DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: Attempt write to past end of device\n"); return -EINVAL; } /* Reject writes, which are not page aligned */ if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) { DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: Attempt to write not page aligned data\n"); return -EINVAL; } /* Grab the lock and see if the device is available */ onenand_get_device(mtd, FL_WRITING); /* Loop until all data write */ while (written < len) { int thislen = min_t(int, mtd->oobblock, len - written); this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobblock); this->write_bufferram(mtd, ONENAND_DATARAM, buf, 0, thislen); this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); this->command(mtd, ONENAND_CMD_PROG, to, mtd->oobblock); onenand_update_bufferram(mtd, to, 1); ret = this->wait(mtd, FL_WRITING); if (ret) { DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: write filaed %d\n", ret); goto out; } written += thislen; /* Only check verify write turn on */ ret = onenand_verify_page(mtd, (u_char *) buf, to); if (ret) { DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: verify failed %d\n", ret); goto out; } if (written == len) break; to += thislen; buf += thislen; }out: /* Deselect and wake up anyone waiting on the device */ onenand_release_device(mtd); *retlen = written; return ret;}/** * onenand_write - [MTD Interface] compability function for onenand_write_ecc * @param mtd MTD device structure * @param to offset to write to * @param len number of bytes to write * @param retlen pointer to variable to store the number of written bytes * @param buf the data to write * * This function simply calls onenand_write_ecc * with oob buffer and oobsel = NULL */static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf){ return onenand_write_ecc(mtd, to, len, retlen, buf, NULL, NULL);}/** * onenand_write_oob - [MTD Interface] OneNAND write out-of-band * @param mtd MTD device structure * @param to offset to write to * @param len number of bytes to write * @param retlen pointer to variable to store the number of written bytes * @param buf the data to write * * OneNAND write out-of-band */static int onenand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf){ struct onenand_chip *this = mtd->priv; int column, ret = 0; int written = 0; DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); /* Initialize retlen, in case of early exit */ *retlen = 0; /* Do not allow writes past end of device */ if (unlikely((to + len) > mtd->size)) { DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: Attempt write to past end of device\n"); return -EINVAL; } /* Grab the lock and see if the device is available */ onenand_get_device(mtd, FL_WRITING); /* Loop until all data write */ while (written < len) { int thislen = min_t(int, mtd->oobsize, len - written); column = to & (mtd->oobsize - 1); this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobsize); /* We send data to spare ram with oobsize * to prevent byte access */ memset(this->page_buf, 0xff, mtd->oobsize); memcpy(this->page_buf + column, buf, thislen); this->write_bufferram(mtd, ONENAND_SPARERAM, this->page_buf, 0, mtd->oobsize); this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize); onenand_update_bufferram(mtd, to, 0); ret = this->wait(mtd, FL_WRITING); if (ret) { DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: write filaed %d\n", ret); goto out; } ret = onenand_verify_oob(mtd, buf, to, thislen); if (ret) { DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: verify failed %d\n", ret); goto out; } written += thislen; if (written == len) break; to += thislen; buf += thislen; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -