[flashrom] [PATCH] Make Bus Pirate init more robust, speed up flashing

Carl-Daniel Hailfinger c-d.hailfinger.devel.2006 at gmx.net
Sun Sep 26 23:20:36 CEST 2010


Thanks to Ian Lesnet for adding a new SPI mode to the Bus Pirate which
is specifically designed for flashrom. It has the potential to speed up
reads and writes a lot.
This patch implements flashrom support for the new SPI mode in a
hopefully backward compatible way.


The new Bus Pirate interface is present since Bus Pirate firmware
version 4.6.
A 16x speedup is expected from this patch for all read operations,
erase operations and for some write operations (chips with page write
only).

I would love to see timing comparisons for read and write. Once
with <4.6 firmware and once with >=4.6 firmware.

The buffer management of all Bus Pirate driver variants has been
revamped to use grow-only buffers with a reasonable initial default
size so realloc() will not have to be called in normal operation.
A side effect is the ability to switch to a static buffer without
major hassle.

Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006 at gmx.net>

Index: flashrom-buspirate_newcommands/buspirate_spi.c
===================================================================
--- flashrom-buspirate_newcommands/buspirate_spi.c	(Revision 1181)
+++ flashrom-buspirate_newcommands/buspirate_spi.c	(Arbeitskopie)
@@ -46,6 +46,57 @@
 #define sp_flush_incoming(...) 0
 #endif
 
+static int buspirate_interface_version;
+static unsigned char *bp_commbuf = NULL;
+static int bp_commbufsize = 0;
+int bp_chunksize;
+
+static int buspirate_commbuf_resize(int bufsize)
+{
+	unsigned char *tmpbuf;
+
+	/* Never shrink. realloc() calls are expensive. */
+	if (bufsize <= bp_commbufsize)
+		return 0;
+
+	tmpbuf = realloc(bp_commbuf, bufsize);
+	if (!tmpbuf) {
+		/* This is debatable. Do we really want to free the existing
+		 * buffer or do we want to keep it around, especially if memory
+		 * is already tight?
+		 */
+		free(bp_commbuf);
+		bp_commbuf = NULL;
+		bp_commbufsize = 0;
+		msg_perr("Out of memory!\n");
+		return OOM_ERROR;
+	}
+
+	bp_commbuf = tmpbuf;
+	bp_commbufsize = bufsize;
+	return 0;
+}
+
+static int buspirate_commbuf_init(int bufsize)
+{
+	bp_commbuf = malloc(bufsize);
+	if (!bp_commbuf) {
+		bp_commbufsize = 0;
+		msg_perr("Out of memory!\n");
+		return OOM_ERROR;
+	}
+
+	bp_commbufsize = bufsize;
+	return 0;
+}
+
+static void buspirate_commbuf_shutdown(void)
+{
+	free(bp_commbuf);
+	bp_commbuf = NULL;
+	bp_commbufsize = 0;
+}
+
 static int buspirate_sendrecv(unsigned char *buf, unsigned int writecnt, unsigned int readcnt)
 {
 	int i, ret = 0;
@@ -131,7 +182,13 @@
 		return ret;
 	free(dev);
 
-	/* This is the brute force version, but it should work. */
+	/* This is the brute force version, but it should work.
+	 * It is guaranteed to fail if a previous flashrom run was aborted
+	 * during a write with the new SPI commands in firmware v4.6 because
+	 * that firmware may wait for up to 4096 bytes of input before
+	 * responding to 0x00 again. The obvious workaround may cause startup
+	 * penalties of more than one second.
+	 */
 	for (i = 0; i < 19; i++) {
 		/* Enter raw bitbang mode */
 		buf[0] = 0x00;
@@ -231,6 +288,42 @@
 		return 1;
 	}
 
+	/* Test combined SPI write/read, length 0. */
+	buf[0] = 0x04;
+	buf[1] = 0;
+	buf[2] = 0;
+	buf[3] = 0;
+	buf[4] = 0;
+	ret = buspirate_sendrecv(buf, 5, 1);
+	if (ret)
+		return 1;
+	if (buf[0] != 0x01) {
+		msg_pdbg("SPI command set v2 not available, using old commands "
+			 "present in firmware <v4.6.\n");
+
+		/* FIXME: Check the error code? */
+		/* We sent 4 bytes of 0x00, so we expect 4 BBIO1 responses. */
+		buspirate_sendrecv(buf, 0, 4 * 5);
+
+		/* Enter raw SPI mode again. */
+		buf[0] = 0x01;
+		/* FIXME: Check the error code? */
+		buspirate_sendrecv(buf, 1, 4);
+
+		buspirate_interface_version = 1;
+		/* Sensible default buffer size. */
+		if (buspirate_commbuf_init(16 + 3))
+			return OOM_ERROR;
+		bp_chunksize = 12;
+	} else {
+		msg_pdbg("Using SPI command set v2.\n"); 
+		buspirate_interface_version = 2;
+		/* Sensible default buffer size. */
+		if (buspirate_commbuf_init(260 + 5))
+			return OOM_ERROR;
+		bp_chunksize = 256;
+	}
+
 	buses_supported = CHIP_BUSTYPE_SPI;
 	spi_controller = SPI_CONTROLLER_BUSPIRATE;
 
@@ -267,73 +360,123 @@
 	ret = serialport_shutdown();
 	if (ret)
 		return ret;
+
+	buspirate_commbuf_shutdown();
+
 	msg_pdbg("Bus Pirate shutdown completed.\n");
 
 	return 0;
 }
 
-int buspirate_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+int buspirate_spi_send_command_v2(unsigned int writecnt, unsigned int readcnt,
 		const unsigned char *writearr, unsigned char *readarr)
 {
-	static unsigned char *buf = NULL;
 	int i = 0, ret = 0;
 
+	if (writecnt > 4096 || readcnt > 4096 || (readcnt + writecnt) > 4096)
+		return SPI_INVALID_LENGTH;
+
+	/* 5 bytes extra for command, writelen, readlen.
+	 * 1 byte extra for Ack/Nack.
+	 */
+	if (buspirate_commbuf_resize(max(writecnt + 5, readcnt + 1)))
+		return OOM_ERROR;
+
+	/* Combined SPI write/read. */
+	bp_commbuf[i++] = 0x04;
+	bp_commbuf[i++] = (writecnt >> 8) & 0xff;
+	bp_commbuf[i++] = writecnt & 0xff;
+	bp_commbuf[i++] = (readcnt >> 8) & 0xff;
+	bp_commbuf[i++] = readcnt & 0xff;
+	memcpy(bp_commbuf + i, writearr, writecnt);
+	
+	ret = buspirate_sendrecv(bp_commbuf, i + writecnt, 1 + readcnt);
+
+	if (ret) {
+		msg_perr("Bus Pirate communication error!\n");
+		return SPI_GENERIC_ERROR;
+	}
+
+	if (bp_commbuf[0] != 0x01) {
+		msg_perr("Protocol error while sending SPI write/read!\n");
+		return SPI_GENERIC_ERROR;
+	}
+
+	/* Skip Ack. */
+	memcpy(readarr, bp_commbuf + 1, readcnt);
+
+	return ret;
+}
+
+int buspirate_spi_send_command_v1(unsigned int writecnt, unsigned int readcnt,
+		const unsigned char *writearr, unsigned char *readarr)
+{
+	int i = 0, ret = 0;
+
 	if (writecnt > 16 || readcnt > 16 || (readcnt + writecnt) > 16)
 		return SPI_INVALID_LENGTH;
 
 	/* 3 bytes extra for CS#, len, CS#. */
-	buf = realloc(buf, writecnt + readcnt + 3);
-	if (!buf) {
-		msg_perr("Out of memory!\n");
-		exit(1); // -1
-	}
+	if (buspirate_commbuf_resize(writecnt + readcnt + 3))
+		return OOM_ERROR;
 
 	/* Assert CS# */
-	buf[i++] = 0x02;
+	bp_commbuf[i++] = 0x02;
 
-	buf[i++] = 0x10 | (writecnt + readcnt - 1);
-	memcpy(buf + i, writearr, writecnt);
+	bp_commbuf[i++] = 0x10 | (writecnt + readcnt - 1);
+	memcpy(bp_commbuf + i, writearr, writecnt);
 	i += writecnt;
-	memset(buf + i, 0, readcnt);
+	memset(bp_commbuf + i, 0, readcnt);
 
 	i += readcnt;
 	/* De-assert CS# */
-	buf[i++] = 0x03;
+	bp_commbuf[i++] = 0x03;
 
-	ret = buspirate_sendrecv(buf, i, i);
+	ret = buspirate_sendrecv(bp_commbuf, i, i);
 
 	if (ret) {
 		msg_perr("Bus Pirate communication error!\n");
 		return SPI_GENERIC_ERROR;
 	}
 
-	if (buf[0] != 0x01) {
+	if (bp_commbuf[0] != 0x01) {
 		msg_perr("Protocol error while lowering CS#!\n");
 		return SPI_GENERIC_ERROR;
 	}
 
-	if (buf[1] != 0x01) {
+	if (bp_commbuf[1] != 0x01) {
 		msg_perr("Protocol error while reading/writing SPI!\n");
 		return SPI_GENERIC_ERROR;
 	}
 
-	if (buf[i - 1] != 0x01) {
+	if (bp_commbuf[i - 1] != 0x01) {
 		msg_perr("Protocol error while raising CS#!\n");
 		return SPI_GENERIC_ERROR;
 	}
 
 	/* Skip CS#, length, writearr. */
-	memcpy(readarr, buf + 2 + writecnt, readcnt);
+	memcpy(readarr, bp_commbuf + 2 + writecnt, readcnt);
 
 	return ret;
 }
 
+int buspirate_spi_send_command(unsigned int writecnt, unsigned int readcnt,
+		const unsigned char *writearr, unsigned char *readarr)
+{
+	switch (buspirate_interface_version) {
+	case 2:
+		return buspirate_spi_send_command_v2(writecnt, readcnt, writearr, readarr);
+	default:
+		return buspirate_spi_send_command_v1(writecnt, readcnt, writearr, readarr);
+	}
+}
+
 int buspirate_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len)
 {
-	return spi_read_chunked(flash, buf, start, len, 12);
+	return spi_read_chunked(flash, buf, start, len, bp_chunksize);
 }
 
 int buspirate_spi_write_256(struct flashchip *flash, uint8_t *buf, int start, int len)
 {
-	return spi_write_chunked(flash, buf, start, len, 12);
+	return spi_write_chunked(flash, buf, start, len, bp_chunksize);
 }
Index: flashrom-buspirate_newcommands/spi.h
===================================================================
--- flashrom-buspirate_newcommands/spi.h	(Revision 1181)
+++ flashrom-buspirate_newcommands/spi.h	(Arbeitskopie)
@@ -125,5 +125,6 @@
 #define SPI_INVALID_LENGTH	-4
 #define SPI_FLASHROM_BUG	-5
 #define SPI_PROGRAMMER_ERROR	-6
+#define OOM_ERROR		-7
 
 #endif		/* !__SPI_H__ */


-- 
http://www.hailfinger.org/





More information about the flashrom mailing list