>From 06a256eec49f2741b9c68818db717f01df6efe6c Mon Sep 17 00:00:00 2001
From: Tadas Slotkus <devtadas@gmail.com>
Date: Tue, 16 Aug 2011 10:05:26 +0300
Subject: [carFl mem 04/21] In erase_and_write_block_helper use chunked reads

erase_and_write_flash now will use only two buffers of 256 bytes size
and filename to use for chunked reads. Also cleanup some unsupported
stuff: erase_and_write_flash won't do any reads if failed, remove only
chip erase codeblock.

Signed-off-by: Tadas Slotkus <devtadas@gmail.com>
---
 flashrom.c |  116 ++++++++++++++++++++++--------------------------------------
 1 files changed, 42 insertions(+), 74 deletions(-)

diff --git a/flashrom.c b/flashrom.c
index 5f87e2f..ad86fd9 100644
--- a/flashrom.c
+++ b/flashrom.c
@@ -1427,45 +1427,56 @@ static int erase_and_write_block_helper(struct flashchip *flash,
 					uint8_t *newcontents,
 					int (*erasefn) (struct flashchip *flash,
 							unsigned int addr,
-							unsigned int len))
+							unsigned int len),
+					const char *filename)
 {
 	int starthere = 0, lenhere = 0, ret = 0, skip = 1, writecount = 0;
+	int starthere2 = 0, lenhere2 = 0;
 	enum write_granularity gran = write_gran_256bytes; /* FIXME */
 
-	/* curcontents and newcontents are opaque to walk_eraseregions, and
-	 * need to be adjusted here to keep the impression of proper abstraction
-	 */
-	curcontents += start;
-	newcontents += start;
-	uint8_t cmpbuf[BUF_SIZE]; //very temporary, see upcoming patches
 	msg_cdbg(":");
 	/* FIXME: Assume 256 byte granularity for now to play it safe. */
-	if (need_erase(curcontents, newcontents, len, gran)) {
+	lenhere2 = BUF_SIZE;
+	for (starthere2 = start; starthere2 < start + len; starthere2 += lenhere2) {
+		flash->read(flash, curcontents, starthere2, lenhere2);
+		read_chunk_from_file(newcontents, starthere2, lenhere2, filename);
+		msg_cdbg("C");
+		if (need_erase(curcontents, newcontents, lenhere2, gran)) {
+			skip = 0; //need erase
+			break;
+		}
+	}
+	if (!skip) { //need erase
 		msg_cdbg("E");
 		ret = erasefn(flash, start, len);
 		if (ret)
 			return ret;
-		if (check_erased_range(flash, start, len, cmpbuf, curcontents)) {
+		if (check_erased_range(flash, start, len, newcontents, curcontents)) {
 			msg_cerr("ERASE FAILED!\n");
 			return -1;
 		}
-		/* Erase was successful. Adjust curcontents. */
-		memset(curcontents, 0xff, len);
+		/* Erase was successful. */
 		skip = 0;
 	}
-	/* get_next_write() sets starthere to a new value after the call. */
-	while ((lenhere = get_next_write(curcontents + starthere,
-					 newcontents + starthere,
-					 len - starthere, &starthere, gran))) {
-		if (!writecount++)
-			msg_cdbg("W");
-		/* Needs the partial write function signature. */
-		ret = flash->write(flash, newcontents + starthere,
-				   start + starthere, lenhere);
-		if (ret)
-			return ret;
-		starthere += lenhere;
-		skip = 0;
+
+	for (starthere2 = start; starthere2 < start + len; starthere2 += lenhere2) {
+		flash->read(flash, curcontents, starthere2, lenhere2);
+		read_chunk_from_file(newcontents, starthere2, lenhere2, filename);
+		starthere = 0; lenhere = 0;
+		/* get_next_write() sets starthere to a new value after the call. */
+		while ((lenhere = get_next_write(curcontents + starthere,
+						 newcontents + starthere,
+						 lenhere2 - starthere, &starthere, gran))) {
+			if (!writecount++)
+				msg_cdbg("W");
+			/* Needs the partial write function signature. */
+			ret = flash->write(flash, newcontents + starthere,
+					   starthere2 + starthere, lenhere);
+			if (ret)
+				return ret;
+			starthere += lenhere;
+			skip = 0;
+		}
 	}
 	if (skip)
 		msg_cdbg("S");
@@ -1481,8 +1492,9 @@ static int walk_eraseregions(struct flashchip *flash, int erasefunction,
 						  int (*erasefn) (
 							struct flashchip *flash,
 							unsigned int addr,
-							unsigned int len)),
-			     void *param1, void *param2)
+							unsigned int len),
+						  const char *filename),
+			     void *param1, void *param2, const char *filename)
 {
 	int i, j;
 	unsigned int start = 0, len;
@@ -1500,7 +1512,7 @@ static int walk_eraseregions(struct flashchip *flash, int erasefunction,
 			msg_cdbg("0x%06x-0x%06x", start,
 				     start + len - 1);
 			if (do_something(flash, start, len, param1, param2,
-					 eraser.block_erase)) {
+					 eraser.block_erase, filename)) {
 				return 1;
 			}
 			start += len;
@@ -1535,21 +1547,12 @@ static int check_block_eraser(const struct flashchip *flash, int k, int log)
 }
 
 int erase_and_write_flash(struct flashchip *flash, uint8_t *oldcontents,
-			  uint8_t *newcontents)
+			  uint8_t *newcontents, const char *filename)
 {
 	int k, ret = 1;
-	uint8_t *curcontents;
-	unsigned long size = flash->total_size * 1024;
 	unsigned int usable_erasefunctions = count_usable_erasers(flash);
 
 	msg_cinfo("Erasing and writing flash chip... ");
-	curcontents = malloc(size);
-	if (!curcontents) {
-		msg_gerr("Out of memory!\n");
-		exit(1);
-	}
-	/* Copy oldcontents to curcontents to avoid clobbering oldcontents. */
-	memcpy(curcontents, oldcontents, size);
 
 	for (k = 0; k < NUM_ERASEFUNCTIONS; k++) {
 		if (k != 0)
@@ -1563,32 +1566,11 @@ int erase_and_write_flash(struct flashchip *flash, uint8_t *oldcontents,
 			continue;
 		usable_erasefunctions--;
 		ret = walk_eraseregions(flash, k, &erase_and_write_block_helper,
-					curcontents, newcontents);
+					oldcontents, newcontents, filename);
 		/* If everything is OK, don't try another erase function. */
 		if (!ret)
 			break;
-		/* Write/erase failed, so try to find out what the current chip
-		 * contents are. If no usable erase functions remain, we can
-		 * skip this: the next iteration will break immediately anyway.
-		 */
-		if (!usable_erasefunctions)
-			continue;
-		/* Reading the whole chip may take a while, inform the user even
-		 * in non-verbose mode.
-		 */
-		msg_cinfo("Reading current flash chip contents... ");
-		if (flash->read(flash, curcontents, 0, size)) {
-			/* Now we are truly screwed. Read failed as well. */
-			msg_cerr("Can't read anymore! Aborting.\n");
-			/* We have no idea about the flash chip contents, so
-			 * retrying with another erase function is pointless.
-			 */
-			break;
-		}
-		msg_cinfo("done. ");
 	}
-	/* Free the scratchpad. */
-	free(curcontents);
 
 	if (ret) {
 		msg_cerr("FAILED!\n");
@@ -1937,20 +1919,6 @@ int doit(struct flashchip *flash, int force, const char *filename, int read_it,
 	 * before we can write.
 	 */
 
-	if (erase_it) {
-		/* FIXME: Do we really want the scary warning if erase failed?
-		 * After all, after erase the chip is either blank or partially
-		 * blank or it has the old contents. A blank chip won't boot,
-		 * so if the user wanted erase and reboots afterwards, the user
-		 * knows very well that booting won't work.
-		 */
-		if (erase_and_write_flash(flash, oldcontents, newcontents)) {
-			emergency_help_message();
-			ret = 1;
-		}
-		goto out;
-	}
-
 	if (write_it || verify_it) {
 		if (read_buf_from_file(newcontents, size, filename)) {
 			ret = 1;
@@ -1984,7 +1952,7 @@ int doit(struct flashchip *flash, int force, const char *filename, int read_it,
 	// ////////////////////////////////////////////////////////////
 
 	if (write_it) {
-		if (erase_and_write_flash(flash, oldcontents, newcontents)) {
+		if (erase_and_write_flash(flash, oldcontents, newcontents, filename)) {
 			msg_cerr("Uh oh. Erase/write failed. Checking if "
 				 "anything changed.\n");
 			if (!flash->read(flash, newcontents, 0, size)) {
-- 
1.7.6

