Skip site navigation (1)Skip section navigation (2)
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>

next in thread | raw e-mail | index | archive | help

--=-Q0PV2kEuZ1OV08CGBS/Z
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: 7bit

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

--=-Q0PV2kEuZ1OV08CGBS/Z
Content-Disposition: attachment; filename="nand.diff"
Content-Type: text/x-patch; name="nand.diff"; charset="UTF-8"
Content-Transfer-Encoding: 7bit

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:

--=-Q0PV2kEuZ1OV08CGBS/Z--




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?1384787290.3934.14.camel>