summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/nand/nand_cdev.c60
-rw-r--r--sys/dev/nand/nand_geom.c58
2 files changed, 100 insertions, 18 deletions
diff --git a/sys/dev/nand/nand_cdev.c b/sys/dev/nand/nand_cdev.c
index ac27ff3..bcfe3ea 100644
--- a/sys/dev/nand/nand_cdev.c
+++ b/sys/dev/nand/nand_cdev.c
@@ -294,19 +294,39 @@ nand_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
struct thread *td)
{
struct nand_chip *chip;
+ struct chip_geom *cg;
struct nand_oob_rw *oob_rw = NULL;
struct nand_raw_rw *raw_rw = NULL;
device_t nandbus;
+ size_t bufsize, len, raw_size;
+ off_t off;
uint8_t *buf = NULL;
int ret = 0;
uint8_t status;
chip = (struct nand_chip *)dev->si_drv1;
+ cg = &chip->chip_geom;
nandbus = device_get_parent(chip->dev);
if ((cmd == NAND_IO_RAW_READ) || (cmd == NAND_IO_RAW_PROG)) {
raw_rw = (struct nand_raw_rw *)data;
- buf = malloc(raw_rw->len, M_NAND, M_WAITOK);
+ raw_size = cg->pgs_per_blk * (cg->page_size + cg->oob_size);
+
+ /* Check if len is not bigger than chip size */
+ if (raw_rw->len > raw_size)
+ return (EFBIG);
+
+ /*
+ * Do not ask for too much memory, in case of large transfers
+ * read/write in 16-pages chunks
+ */
+ bufsize = 16 * (cg->page_size + cg->oob_size);
+ if (raw_rw->len < bufsize)
+ bufsize = raw_rw->len;
+
+ buf = malloc(bufsize, M_NAND, M_WAITOK);
+ len = raw_rw->len;
+ off = 0;
}
switch(cmd) {
case NAND_IO_ERASE:
@@ -335,19 +355,37 @@ nand_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
break;
case NAND_IO_RAW_PROG:
- ret = copyin(raw_rw->data, buf, raw_rw->len);
- if (ret)
- break;
- ret = nand_prog_pages_raw(chip, raw_rw->off, buf,
- raw_rw->len);
+ while (len > 0) {
+ if (len < bufsize)
+ bufsize = len;
+ ret = copyin(raw_rw->data + off, buf, bufsize);
+ if (ret)
+ break;
+ ret = nand_prog_pages_raw(chip, raw_rw->off + off, buf,
+ bufsize);
+ if (ret)
+ break;
+ len -= bufsize;
+ off += bufsize;
+ }
break;
case NAND_IO_RAW_READ:
- ret = nand_read_pages_raw(chip, raw_rw->off, buf,
- raw_rw->len);
- if (ret)
- break;
- ret = copyout(buf, raw_rw->data, raw_rw->len);
+ while (len > 0) {
+ if (len < bufsize)
+ bufsize = len;
+
+ ret = nand_read_pages_raw(chip, raw_rw->off + off, buf,
+ bufsize);
+ if (ret)
+ break;
+
+ ret = copyout(buf, raw_rw->data + off, bufsize);
+ if (ret)
+ break;
+ len -= bufsize;
+ off += bufsize;
+ }
break;
case NAND_IO_PAGE_STAT:
diff --git a/sys/dev/nand/nand_geom.c b/sys/dev/nand/nand_geom.c
index 2c4915b..f17ee60 100644
--- a/sys/dev/nand/nand_geom.c
+++ b/sys/dev/nand/nand_geom.c
@@ -193,20 +193,41 @@ nand_ioctl(struct disk *ndisk, u_long cmd, void *data, int fflag,
struct thread *td)
{
struct nand_chip *chip;
+ struct chip_geom *cg;
struct nand_oob_rw *oob_rw = NULL;
struct nand_raw_rw *raw_rw = NULL;
device_t nandbus;
+ size_t bufsize, len, raw_size;
+ off_t off;
uint8_t *buf = NULL;
int ret = 0;
uint8_t status;
chip = (struct nand_chip *)ndisk->d_drv1;
+ cg = &chip->chip_geom;
nandbus = device_get_parent(chip->dev);
if ((cmd == NAND_IO_RAW_READ) || (cmd == NAND_IO_RAW_PROG)) {
raw_rw = (struct nand_raw_rw *)data;
- buf = malloc(raw_rw->len, M_NAND, M_WAITOK);
+ raw_size = cg->pgs_per_blk * (cg->page_size + cg->oob_size);
+
+ /* Check if len is not bigger than chip size */
+ if (raw_rw->len > raw_size)
+ return (EFBIG);
+
+ /*
+ * Do not ask for too much memory, in case of large transfers
+ * read/write in 16-pages chunks
+ */
+ bufsize = 16 * (cg->page_size + cg->oob_size);
+ if (raw_rw->len < bufsize)
+ bufsize = raw_rw->len;
+
+ buf = malloc(bufsize, M_NAND, M_WAITOK);
+ len = raw_rw->len;
+ off = 0;
}
+
switch (cmd) {
case NAND_IO_ERASE:
ret = nand_erase_blocks(chip, ((off_t *)data)[0],
@@ -234,15 +255,38 @@ nand_ioctl(struct disk *ndisk, u_long cmd, void *data, int fflag,
break;
case NAND_IO_RAW_PROG:
- copyin(raw_rw->data, buf, raw_rw->len);
- ret = nand_prog_pages_raw(chip, raw_rw->off, buf,
- raw_rw->len);
+ while (len > 0) {
+ if (len < bufsize)
+ bufsize = len;
+
+ ret = copyin(raw_rw->data + off, buf, bufsize);
+ if (ret)
+ break;
+ ret = nand_prog_pages_raw(chip, raw_rw->off + off, buf,
+ bufsize);
+ if (ret)
+ break;
+ len -= bufsize;
+ off += bufsize;
+ }
break;
case NAND_IO_RAW_READ:
- ret = nand_read_pages_raw(chip, raw_rw->off, buf,
- raw_rw->len);
- copyout(buf, raw_rw->data, raw_rw->len);
+ while (len > 0) {
+ if (len < bufsize)
+ bufsize = len;
+
+ ret = nand_read_pages_raw(chip, raw_rw->off + off, buf,
+ bufsize);
+ if (ret)
+ break;
+
+ ret = copyout(buf, raw_rw->data + off, bufsize);
+ if (ret)
+ break;
+ len -= bufsize;
+ off += bufsize;
+ }
break;
case NAND_IO_GET_CHIP_PARAM:
OpenPOWER on IntegriCloud