Date: Mon, 18 Nov 2013 16:08:10 +0100 From: Grzegorz Bernacki <gjb@semihalf.com> To: freebsd-embedded@FreeBSD.org Subject: nand_geom and nand_cdev fixes Message-ID: <1384787290.3934.14.camel@hp8.semihalf.com>
index | next in thread | raw e-mail
[-- Attachment #1 --]
Hi,
I've made two fixes in nand_geom.c and nand_cdev.c. First one is related
to allocating internal buffer for reading/programming data. To avoid
allocation of memory which is too big, I allocate buffer which has size
of 16 pages and read/program data in ten-pages chunks.
Second change is to skip copyout() when nand_read_pages_raw() fails.
I've attached patch with these changes. Can I ask for test/review of
these changes?
thanks,
grzesiek
[-- Attachment #2 --]
Index: sys/dev/nand/nand_cdev.c
===================================================================
--- sys/dev/nand/nand_cdev.c (wersja 258161)
+++ sys/dev/nand/nand_cdev.c (kopia robocza)
@@ -294,19 +294,39 @@
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,35 @@
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 == 0)
+ ret = copyout(buf, raw_rw->data + off, bufsize);
+ if (ret)
+ break;
+ len -= bufsize;
+ off += bufsize;
+ }
break;
case NAND_IO_PAGE_STAT:
Index: sys/dev/nand/nand_geom.c
===================================================================
--- sys/dev/nand/nand_geom.c (wersja 258161)
+++ sys/dev/nand/nand_geom.c (kopia robocza)
@@ -193,20 +193,41 @@
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,36 @@
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 == 0)
+ ret = copyout(buf, raw_rw->data + off, bufsize);
+ if (ret)
+ break;
+ len -= bufsize;
+ off += bufsize;
+ }
break;
case NAND_IO_GET_CHIP_PARAM:
help
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?1384787290.3934.14.camel>
