Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 14 Sep 2012 20:36:51 GMT
From:      Brooks Davis <brooks@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 217312 for review
Message-ID:  <201209142036.q8EKapUM052746@skunkworks.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@217312?ac=10

Change 217312 by brooks@brooks_zenith on 2012/09/14 20:35:52

	As an optimization, keep an unaltered copy of the block being
	altered and use this to avoid erase cycles when they are unneeded
	as well as avoiding writing unchanged words.

Affected files ...

.. //depot/projects/ctsrd/beribsd/src/sys/dev/cfi/cfi_core.c#4 edit
.. //depot/projects/ctsrd/beribsd/src/sys/dev/cfi/cfi_dev.c#3 edit
.. //depot/projects/ctsrd/beribsd/src/sys/dev/cfi/cfi_var.h#3 edit

Differences ...

==== //depot/projects/ctsrd/beribsd/src/sys/dev/cfi/cfi_core.c#4 (text+ko) ====

@@ -386,9 +386,9 @@
 		uint8_t		*x8;
 		uint16_t	*x16;
 		uint32_t	*x32;
-	} ptr;
+	} ptr, cpyprt;
 	register_t intr;
-	int error, i;
+	int error, i, neederase = 0;
 
 	switch (sc->sc_cmdset) {
 	case CFI_VEND_INTEL_ECS:
@@ -399,31 +399,60 @@
 		break;
 	}
 
-	/* Erase the block. */
-	switch (sc->sc_cmdset) {
-	case CFI_VEND_INTEL_ECS:
-	case CFI_VEND_INTEL_SCS:
-		cfi_write(sc, sc->sc_wrofs, CFI_BCS_BLOCK_ERASE);
-		cfi_write(sc, sc->sc_wrofs, CFI_BCS_CONFIRM);
-		break;
-	case CFI_VEND_AMD_SCS:
-	case CFI_VEND_AMD_ECS:
-		cfi_amd_write(sc, sc->sc_wrofs, AMD_ADDR_START,
-		    CFI_AMD_ERASE_SECTOR);
-		cfi_amd_write(sc, sc->sc_wrofs, 0, CFI_AMD_BLOCK_ERASE);
-		break;
-	default:
-		/* Better safe than sorry... */
-		return (ENODEV);
-	}
-	error = cfi_wait_ready(sc, sc->sc_wrofs, sc->sc_erase_timeout);
-	if (error)
-		goto out;
+	/* Check if an erase is required. */
+	for (i = 0; i < sc->sc_wrbufsz; i++)
+		if ((sc->sc_wrbuf[i] & sc->sc_wrbufcpy[i]) != sc->sc_wrbuf[i]) {
+			neederase = 1;
+			break;
+		}
+
+	if (neederase) {
+		/* Erase the block. */
+		switch (sc->sc_cmdset) {
+		case CFI_VEND_INTEL_ECS:
+		case CFI_VEND_INTEL_SCS:
+			cfi_write(sc, sc->sc_wrofs, CFI_BCS_BLOCK_ERASE);
+			cfi_write(sc, sc->sc_wrofs, CFI_BCS_CONFIRM);
+			break;
+		case CFI_VEND_AMD_SCS:
+		case CFI_VEND_AMD_ECS:
+			cfi_amd_write(sc, sc->sc_wrofs, AMD_ADDR_START,
+			    CFI_AMD_ERASE_SECTOR);
+			cfi_amd_write(sc, sc->sc_wrofs, 0, CFI_AMD_BLOCK_ERASE);
+			break;
+		default:
+			/* Better safe than sorry... */
+			return (ENODEV);
+		}
+		error = cfi_wait_ready(sc, sc->sc_wrofs, sc->sc_erase_timeout);
+		if (error)
+			goto out;
+	} else
+		error = 0;
 
 	/* Write the block. */
 	ptr.x8 = sc->sc_wrbuf;
+	cpyprt.x8 = sc->sc_wrbufcpy;
 	for (i = 0; i < sc->sc_wrbufsz; i += sc->sc_width) {
 
+		/* Avoid writing unless we are actually changing bits */
+		if (!neederase) {
+			switch (sc->sc_width) {
+			case 1:
+				if(*(ptr.x8 + i) == *(cpyprt.x8 + i))
+					continue;
+				break;
+			case 2:
+				if(*(ptr.x16 + i / 2) == *(cpyprt.x16 + i / 2))
+					continue;
+				break;
+			case 4:
+				if(*(ptr.x32 + i / 4) == *(cpyprt.x32 + i / 4))
+					continue;
+				break;
+			}
+		}
+
 		/*
 		 * Make sure the command to start a write and the
 		 * actual write happens back-to-back without any
@@ -444,15 +473,15 @@
 		switch (sc->sc_width) {
 		case 1:
 			bus_space_write_1(sc->sc_tag, sc->sc_handle,
-			    sc->sc_wrofs + i, *(ptr.x8)++);
+			    sc->sc_wrofs + i, *(ptr.x8 + i));
 			break;
 		case 2:
 			bus_space_write_2(sc->sc_tag, sc->sc_handle,
-			    sc->sc_wrofs + i, *(ptr.x16)++);
+			    sc->sc_wrofs + i, *(ptr.x16 + i / 2));
 			break;
 		case 4:
 			bus_space_write_4(sc->sc_tag, sc->sc_handle,
-			    sc->sc_wrofs + i, *(ptr.x32)++);
+			    sc->sc_wrofs + i, *(ptr.x32 + i / 4));
 			break;
 		}
 

==== //depot/projects/ctsrd/beribsd/src/sys/dev/cfi/cfi_dev.c#3 (text+ko) ====

@@ -72,7 +72,8 @@
  * Begin writing into a new block/sector.  We read the sector into
  * memory and keep updating that, until we move into another sector
  * or the process stops writing. At that time we write the whole
- * sector to flash (see cfi_block_finish).
+ * sector to flash (see cfi_block_finish).  To avoid unneeded erase
+ * cycles, keep a pristine copy of the sector on hand.
  */
 int
 cfi_block_start(struct cfi_softc *sc, u_int ofs)
@@ -116,6 +117,8 @@
 			break;
 		}
 	}
+	sc->sc_wrbufcpy = malloc(sc->sc_wrbufsz, M_TEMP, M_WAITOK);
+	memcpy(sc->sc_wrbufcpy, sc->sc_wrbuf, sc->sc_wrbufsz);
 	sc->sc_writing = 1;
 	return (0);
 }
@@ -131,6 +134,7 @@
 
 	error = cfi_write_block(sc);
 	free(sc->sc_wrbuf, M_TEMP);
+	free(sc->sc_wrbufcpy, M_TEMP);
 	sc->sc_wrbuf = NULL;
 	sc->sc_wrbufsz = 0;
 	sc->sc_wrofs = 0;

==== //depot/projects/ctsrd/beribsd/src/sys/dev/cfi/cfi_var.h#3 (text+ko) ====

@@ -58,6 +58,7 @@
 	struct proc	*sc_opened;	/* Process that has us opened. */
 
 	u_char		*sc_wrbuf;
+	u_char		*sc_wrbufcpy;
 	u_int		sc_wrbufsz;
 	u_int		sc_wrofs;
 	u_int		sc_writing;



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