[flashrom] [PATCH 1/3] Prepare ichspi for check_trans().

Stefan Tauner stefan.tauner at student.tuwien.ac.at
Sat Sep 29 18:41:39 CEST 2012


Signed-off-by: Stefan Tauner <stefan.tauner at student.tuwien.ac.at>
---
 flash.h  |    1 +
 ichspi.c |  247 +++++++++++++++++++++++++++++++++++---------------------------
 2 files changed, 142 insertions(+), 106 deletions(-)

diff --git a/flash.h b/flash.h
index 4913536..3230849 100644
--- a/flash.h
+++ b/flash.h
@@ -24,6 +24,7 @@
 #ifndef __FLASH_H__
 #define __FLASH_H__ 1
 
+#include <stdbool.h>
 #include <stdint.h>
 #include <stddef.h>
 #ifdef _WIN32
diff --git a/ichspi.c b/ichspi.c
index 8dd1893..142a122 100644
--- a/ichspi.c
+++ b/ichspi.c
@@ -370,66 +370,60 @@ static void prettyprint_ich9_reg_ssfc(uint32_t reg_val)
 	pprint_reg(SSFC, SCF, reg_val, "\n");
 }
 
-static uint8_t lookup_spi_type(uint8_t opcode)
+static uint8_t determine_spitype(uint8_t opcode, unsigned int writecnt, unsigned int readcnt)
 {
-	int a;
-
-	for (a = 0; a < ARRAY_SIZE(POSSIBLE_OPCODES); a++) {
-		if (POSSIBLE_OPCODES[a].opcode == opcode)
-			return POSSIBLE_OPCODES[a].spi_type;
+	int i;
+	for (i = 0; i < ARRAY_SIZE(POSSIBLE_OPCODES); i++) {
+		if (POSSIBLE_OPCODES[i].opcode == opcode)
+			return POSSIBLE_OPCODES[i].spi_type;
 	}
 
-	return 0xFF;
+	/* Try to guess spi type from read/write sizes.
+	 * The following valid writecnt/readcnt combinations exist:
+	 * writecnt  = 4, readcnt >= 0
+	 * writecnt  = 1, readcnt >= 0
+	 * writecnt >= 4, readcnt  = 0
+	 * writecnt >= 1, readcnt  = 0
+	 * writecnt >= 1 is guaranteed for all commands.
+	 */
+	msg_pspew("Need to guess spitype from payload lengths.\n");
+	if (readcnt == 0)
+		/* if readcnt=0 and writecount >= 4, we don't know if it is WRITE_NO_ADDRESS
+		 * or WRITE_WITH_ADDRESS. But if we use WRITE_NO_ADDRESS and the first 3 data
+		 * bytes are actual the address, they go to the bus anyhow
+		 */
+		return SPI_OPCODE_TYPE_WRITE_NO_ADDRESS;
+	else if (writecnt == 1) // and readcnt is > 0
+		return SPI_OPCODE_TYPE_READ_NO_ADDRESS;
+	else if (writecnt == 4) // and readcnt is > 0
+		return SPI_OPCODE_TYPE_READ_WITH_ADDRESS;
+	else // we have an invalid case
+		return 0xFF;
 }
 
-static int reprogram_opcode_on_the_fly(uint8_t opcode, unsigned int writecnt, unsigned int readcnt)
+/* FIXME: check and use return code of program_opcodes*/
+static int reprogram_opcode_on_the_fly(uint8_t opcode, uint8_t spi_type, unsigned int writecnt, unsigned int readcnt)
 {
-	uint8_t spi_type;
-
-	spi_type = lookup_spi_type(opcode);
-	if (spi_type > 3) {
-		/* Try to guess spi type from read/write sizes.
-		 * The following valid writecnt/readcnt combinations exist:
-		 * writecnt  = 4, readcnt >= 0
-		 * writecnt  = 1, readcnt >= 0
-		 * writecnt >= 4, readcnt  = 0
-		 * writecnt >= 1, readcnt  = 0
-		 * writecnt >= 1 is guaranteed for all commands.
-		 */
-		if (readcnt == 0)
-			/* if readcnt=0 and writecount >= 4, we don't know if it is WRITE_NO_ADDRESS
-			 * or WRITE_WITH_ADDRESS. But if we use WRITE_NO_ADDRESS and the first 3 data
-			 * bytes are actual the address, they go to the bus anyhow
-			 */
-			spi_type = SPI_OPCODE_TYPE_WRITE_NO_ADDRESS;
-		else if (writecnt == 1) // and readcnt is > 0
-			spi_type = SPI_OPCODE_TYPE_READ_NO_ADDRESS;
-		else if (writecnt == 4) // and readcnt is > 0
-			spi_type = SPI_OPCODE_TYPE_READ_WITH_ADDRESS;
-		else // we have an invalid case
-			return SPI_INVALID_LENGTH;
-	}
-	int oppos = 2;	// use original JEDEC_BE_D8 offset
+	const int oppos = 2;	// use original JEDEC_BE_D8 offset
 	curopcodes->opcode[oppos].opcode = opcode;
 	curopcodes->opcode[oppos].spi_type = spi_type;
 	program_opcodes(curopcodes, 0);
-	oppos = find_opcode(curopcodes, opcode);
 	msg_pdbg2("on-the-fly OPCODE (0x%02X) re-programmed, op-pos=%d\n", opcode, oppos);
-	return oppos;
+	return 0;
 }
 
 static int find_opcode(OPCODES *op, uint8_t opcode)
 {
-	int a;
+	int i;
 
 	if (op == NULL) {
 		msg_perr("\n%s: null OPCODES pointer!\n", __func__);
 		return -1;
 	}
 
-	for (a = 0; a < 8; a++) {
-		if (op->opcode[a].opcode == opcode)
-			return a;
+	for (i = 0; i < 8; i++) {
+		if (op->opcode[i].opcode == opcode)
+			return i;
 	}
 
 	return -1;
@@ -505,6 +499,7 @@ static int generate_opcodes(OPCODES * op)
 	return 0;
 }
 
+/* FIXME: verify */
 static int program_opcodes(OPCODES *op, int enable_undo)
 {
 	uint8_t a;
@@ -720,7 +715,7 @@ static int ich7_run_opcode(OPCODE op, uint32_t offset,
 	uint32_t temp32;
 	uint16_t temp16;
 	uint64_t opmenu;
-	int opcode_index;
+	int oppos;
 
 	/* Is it a write command? */
 	if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)
@@ -765,17 +760,17 @@ static int ich7_run_opcode(OPCODE op, uint32_t offset,
 	opmenu = REGREAD32(ICH7_REG_OPMENU);
 	opmenu |= ((uint64_t)REGREAD32(ICH7_REG_OPMENU + 4)) << 32;
 
-	for (opcode_index = 0; opcode_index < 8; opcode_index++) {
+	for (oppos = 0; oppos < 8; oppos++) {
 		if ((opmenu & 0xff) == op.opcode) {
 			break;
 		}
 		opmenu >>= 8;
 	}
-	if (opcode_index == 8) {
+	if (oppos == 8) {
 		msg_pdbg("Opcode %x not found.\n", op.opcode);
 		return 1;
 	}
-	temp16 |= ((uint16_t) (opcode_index & 0x07)) << 4;
+	temp16 |= ((uint16_t) (oppos & 0x07)) << 4;
 
 	timeout = 100 * 60;	/* 60 ms are 9.6 million cycles at 16 MHz. */
 	/* Handle Atomic. Atomic commands include three steps:
@@ -837,7 +832,7 @@ static int ich9_run_opcode(OPCODE op, uint32_t offset,
 	int timeout;
 	uint32_t temp32;
 	uint64_t opmenu;
-	int opcode_index;
+	int oppos;
 
 	/* Is it a write command? */
 	if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)
@@ -887,17 +882,17 @@ static int ich9_run_opcode(OPCODE op, uint32_t offset,
 	opmenu = REGREAD32(ICH9_REG_OPMENU);
 	opmenu |= ((uint64_t)REGREAD32(ICH9_REG_OPMENU + 4)) << 32;
 
-	for (opcode_index = 0; opcode_index < 8; opcode_index++) {
+	for (oppos = 0; oppos < 8; oppos++) {
 		if ((opmenu & 0xff) == op.opcode) {
 			break;
 		}
 		opmenu >>= 8;
 	}
-	if (opcode_index == 8) {
+	if (oppos == 8) {
 		msg_pdbg("Opcode %x not found.\n", op.opcode);
 		return 1;
 	}
-	temp32 |= ((uint32_t) (opcode_index & 0x07)) << (8 + 4);
+	temp32 |= ((uint32_t) (oppos & 0x07)) << (8 + 4);
 
 	timeout = 100 * 60;	/* 60 ms are 9.6 million cycles at 16 MHz. */
 	/* Handle Atomic. Atomic commands include three steps:
@@ -982,36 +977,56 @@ static int run_opcode(const struct flashctx *flash, OPCODE op, uint32_t offset,
 	}
 }
 
-static int ich_spi_send_command(struct flashctx *flash, unsigned int writecnt,
-				unsigned int readcnt,
-				const unsigned char *writearr,
-				unsigned char *readarr)
+/* flag offsets of prepare_opcode */
+#define ICH_DRYRUN	0
+static int prepare_opcode(struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
+			const unsigned char *writearr, uint8_t flags, OPCODE **op);
+
+/* Check command and prepare the appropriate opcode.
+ * The selected OPCODE will be returned by opcodep if it can be determined.
+ * If the dryrun flag is set, try do determine opcode sanity and availability only, do not change hw state
+ * (i.e. do not touch OPMENU). In that case opcodep is undefined.
+ * Returns 0 on success, or SPI_INVALID_* if the command would not work on this board. */
+static int prepare_opcode(struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
+			const unsigned char *writearr, uint8_t flags, OPCODE **opcodep)
 {
-	int result;
-	int opcode_index = -1;
-	const unsigned char cmd = *writearr;
-	OPCODE *opcode;
-	uint32_t addr = 0;
-	uint8_t *data;
-	int count;
+	OPCODE *opcode = NULL;
+	OPCODE emu_op = {0};
+	bool dryrun = (flags & (1 << ICH_DRYRUN));
+	if (writecnt == 0)
+		return SPI_INVALID_LENGTH;
 
-	/* find cmd in opcodes-table */
-	opcode_index = find_opcode(curopcodes, cmd);
-	if (opcode_index == -1) {
-		if (!ichspi_lock)
-			opcode_index = reprogram_opcode_on_the_fly(cmd, writecnt, readcnt);
-		if (opcode_index == SPI_INVALID_LENGTH) {
-			msg_pdbg("OPCODE 0x%02x has unsupported length, will not execute.\n", cmd);
+	/* ensure that the requested opcode is available */
+	int oppos = find_opcode(curopcodes, writearr[0]);
+	if (oppos >= 0) {
+		opcode = &(curopcodes->opcode[oppos]);
+	} else {
+		uint8_t spi_type = determine_spitype(writearr[0], writecnt, readcnt);
+		if (spi_type == 0xFF) {
+			if (!dryrun)
+				msg_pdbg("Could not determine spitype for opcode 0x%02x.\n", writearr[0]);
 			return SPI_INVALID_LENGTH;
-		} else if (opcode_index == -1) {
-			msg_pdbg("Invalid OPCODE 0x%02x, will not execute.\n",
-				 cmd);
+		}
+		if (ichspi_lock) {
+			if (!dryrun)
+				msg_pdbg("OPCODES locked down and do not contain 0x%02x, can not execute.\n",
+					 writearr[0]);
 			return SPI_INVALID_OPCODE;
+		} else {
+			/* In a dryrun we expect that reprogramming works successfully, but we need to create
+			 * an OPCODE object for the tests below. */
+			if (dryrun) {
+				emu_op.opcode = writearr[0];
+				emu_op.spi_type = spi_type;
+				opcode = &emu_op;
+			} else {
+				reprogram_opcode_on_the_fly(writearr[0], spi_type, writecnt, readcnt);
+				oppos = find_opcode(curopcodes, writearr[0]);
+				opcode = &(curopcodes->opcode[oppos]);
+			}
 		}
 	}
 
-	opcode = &(curopcodes->opcode[opcode_index]);
-
 	/* The following valid writecnt/readcnt combinations exist:
 	 * writecnt  = 4, readcnt >= 0
 	 * writecnt  = 1, readcnt >= 0
@@ -1019,49 +1034,66 @@ static int ich_spi_send_command(struct flashctx *flash, unsigned int writecnt,
 	 * writecnt >= 1, readcnt  = 0
 	 * writecnt >= 1 is guaranteed for all commands.
 	 */
-	if ((opcode->spi_type == SPI_OPCODE_TYPE_READ_WITH_ADDRESS) &&
-	    (writecnt != 4)) {
-		msg_perr("%s: Internal command size error for opcode "
-			"0x%02x, got writecnt=%i, want =4\n", __func__, cmd,
-			writecnt);
+	if ((opcode->spi_type == SPI_OPCODE_TYPE_READ_WITH_ADDRESS) && (writecnt != 4)) {
+		if (!dryrun)
+			msg_perr("%s: Internal command size error for opcode 0x%02x, got writecnt=%i, want =4\n",
+			 __func__, writearr[0], writecnt);
 		return SPI_INVALID_LENGTH;
 	}
-	if ((opcode->spi_type == SPI_OPCODE_TYPE_READ_NO_ADDRESS) &&
-	    (writecnt != 1)) {
-		msg_perr("%s: Internal command size error for opcode "
-			"0x%02x, got writecnt=%i, want =1\n", __func__, cmd,
-			writecnt);
+	if ((opcode->spi_type == SPI_OPCODE_TYPE_READ_NO_ADDRESS) && (writecnt != 1)) {
+		if (!dryrun)
+			msg_perr("%s: Internal command size error for opcode 0x%02x, got writecnt=%i, want =1\n",
+				 __func__, writearr[0], writecnt);
 		return SPI_INVALID_LENGTH;
 	}
-	if ((opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) &&
-	    (writecnt < 4)) {
-		msg_perr("%s: Internal command size error for opcode "
-			"0x%02x, got writecnt=%i, want >=4\n", __func__, cmd,
-			writecnt);
+	if ((opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) && (writecnt < 4)) {
+		if (!dryrun)
+			msg_perr("%s: Internal command size error for opcode 0x%02x, got writecnt=%i, want >=4\n",
+				 __func__, writearr[0], writecnt);
 		return SPI_INVALID_LENGTH;
 	}
 	if (((opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) ||
 	     (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)) &&
 	    (readcnt)) {
-		msg_perr("%s: Internal command size error for opcode "
-			"0x%02x, got readcnt=%i, want =0\n", __func__, cmd,
-			readcnt);
+		if (!dryrun)
+			msg_perr("%s: Internal command size error for opcode 0x%02x, got readcnt=%i, want =0\n",
+				 __func__, writearr[0], readcnt);
 		return SPI_INVALID_LENGTH;
 	}
 
-	/* if opcode-type requires an address */
+	/* if opcode-type requires an address we check if it is below the allowed base. */
 	if (opcode->spi_type == SPI_OPCODE_TYPE_READ_WITH_ADDRESS ||
 	    opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) {
-		addr = (writearr[1] << 16) |
-		    (writearr[2] << 8) | (writearr[3] << 0);
+		uint32_t addr = (writearr[1] << 16) | (writearr[2] << 8) | (writearr[3] << 0);
 		if (addr < ichspi_bbar) {
-			msg_perr("%s: Address 0x%06x below allowed "
-				 "range 0x%06x-0xffffff\n", __func__,
-				 addr, ichspi_bbar);
+			msg_perr("%s: Address 0x%06x below allowed range 0x%06x-0xffffff\n",
+				 __func__, addr, ichspi_bbar);
 			return SPI_INVALID_ADDRESS;
 		}
 	}
 
+	if (opcodep != NULL)
+		*opcodep = opcode;
+	return 0;
+}
+
+static int ich_spi_send_command(struct flashctx *flash, unsigned int writecnt,
+				unsigned int readcnt,
+				const unsigned char *writearr,
+				unsigned char *readarr)
+{
+	OPCODE *opcode;
+	uint32_t addr;
+	uint8_t *data;
+	int count;
+
+	int result = prepare_opcode(flash, writecnt, readcnt, writearr, (0 << ICH_DRYRUN), &opcode);
+	if (result != 0) {
+		msg_pspew("%s called with an unsupported transaction layout: readcnt = %d, writecnt = %d.\n",
+			  __func__, readcnt, writecnt);
+		return result;
+	}
+
 	/* Translate read/write array/count.
 	 * The maximum data length is identical for the maximum read length and
 	 * for the maximum write length excluding opcode and address. Opcode and
@@ -1080,6 +1112,7 @@ static int ich_spi_send_command(struct flashctx *flash, unsigned int writecnt,
 		count = readcnt;
 	}
 
+	addr = (writearr[1] << 16) | (writearr[2] << 8) | (writearr[3] << 0);
 	result = run_opcode(flash, *opcode, addr, count, data);
 	if (result) {
 		msg_pdbg("Running OPCODE 0x%02x failed ", opcode->opcode);
@@ -1358,17 +1391,17 @@ static int ich_hwseq_write(struct flashctx *flash, uint8_t *buf,
 	return 0;
 }
 
-static int ich_spi_send_multicommand(struct flashctx *flash,
-				     struct spi_command *cmds)
+static int ich_spi_send_multicommand(struct flashctx *flash, struct spi_command *cmds)
 {
 	int ret = 0;
 	int i;
 	int oppos, preoppos;
 	for (; (cmds->writecnt || cmds->readcnt) && !ret; cmds++) {
-		if ((cmds + 1)->writecnt || (cmds + 1)->readcnt) {
+		struct spi_command *cmd_nxt = cmds + 1;
+		if (cmd_nxt->writecnt || cmd_nxt->readcnt) {
 			/* Next command is valid. */
 			preoppos = find_preop(curopcodes, cmds->writearr[0]);
-			oppos = find_opcode(curopcodes, (cmds + 1)->writearr[0]);
+			oppos = find_opcode(curopcodes, cmd_nxt->writearr[0]);
 			if ((oppos == -1) && (preoppos != -1)) {
 				/* Current command is listed as preopcode in
 				 * ICH struct OPCODES, but next command is not
@@ -1376,13 +1409,10 @@ static int ich_spi_send_multicommand(struct flashctx *flash,
 				 * Check for command sanity, then
 				 * try to reprogram the ICH opcode list.
 				 */
-				if (find_preop(curopcodes,
-					       (cmds + 1)->writearr[0]) != -1) {
-					msg_perr("%s: Two subsequent "
-						"preopcodes 0x%02x and 0x%02x, "
+				if (find_preop(curopcodes, cmd_nxt->writearr[0]) != -1) {
+					msg_perr("%s: Two subsequent preopcodes 0x%02x and 0x%02x, "
 						"ignoring the first.\n",
-						__func__, cmds->writearr[0],
-						(cmds + 1)->writearr[0]);
+						__func__, cmds->writearr[0], cmd_nxt->writearr[0]);
 					continue;
 				}
 				/* If the chipset is locked down, we'll fail
@@ -1390,7 +1420,12 @@ static int ich_spi_send_multicommand(struct flashctx *flash,
 				 * No need to bother with fixups.
 				 */
 				if (!ichspi_lock) {
-					oppos = reprogram_opcode_on_the_fly((cmds + 1)->writearr[0], (cmds + 1)->writecnt, (cmds + 1)->readcnt);
+					uint8_t spi_type = determine_spitype(cmd_nxt->writearr[0], cmd_nxt->writecnt, cmd_nxt->readcnt);
+					if (spi_type == 0xFF) {
+						msg_pdbg("Could not determine spitype for opcode 0x%02x.\n", cmd_nxt->writearr[0]);
+						return SPI_INVALID_LENGTH;
+					}
+					oppos = reprogram_opcode_on_the_fly(cmd_nxt->writearr[0], spi_type, cmd_nxt->writecnt, cmd_nxt->readcnt);
 					if (oppos == -1)
 						continue;
 					curopcodes->opcode[oppos].atomic = preoppos + 1;
-- 
Kind regards, Stefan Tauner





More information about the flashrom mailing list