- Introduce prepare_opcode() which does: * find the offset of an opcode or reprogram the OPMENU as necessary * check if the writecnt and readcnt are legit for the transaction type * ensure that the allowed BBAR is obeyed. - Merge lookup_spi_type() and parts of reprogram_opcode_on_the_fly() into determine_spitype(). - Verify the writes in program_opcodes() and use it in error handling. - Refactor ich_spi_send_multicommand() to utilize above changes. - General cleanup of variable and constant names, among others: * opcode_index -> oppos everywhere * shortening of SPI_OPCODE_TYPE_*
Signed-off-by: Stefan Tauner stefan.tauner@student.tuwien.ac.at --- flash.h | 1 + ichspi.c | 347 +++++++++++++++++++++++++++++++++++--------------------------- 2 files changed, 196 insertions(+), 152 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..e60913c 100644 --- a/ichspi.c +++ b/ichspi.c @@ -135,10 +135,10 @@ #define FPB_FPBA (0x1FFF << FPB_FPBA_OFF)
// ICH9R SPI commands -#define SPI_OPCODE_TYPE_READ_NO_ADDRESS 0 -#define SPI_OPCODE_TYPE_WRITE_NO_ADDRESS 1 -#define SPI_OPCODE_TYPE_READ_WITH_ADDRESS 2 -#define SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS 3 +#define READING_OP_NO_ADDR 0 +#define WRITING_OP_NO_ADDR 1 +#define READING_OP_WITH_ADDR 2 +#define WRITING_OP_WITH_ADDR 3
// ICH7 registers #define ICH7_REG_SPIS 0x00 /* 16 Bits */ @@ -261,14 +261,14 @@ static OPCODES O_ST_M25P = { JEDEC_EWSR, }, { - {JEDEC_BYTE_PROGRAM, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 0}, // Write Byte - {JEDEC_READ, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Read Data - {JEDEC_BE_D8, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 0}, // Erase Sector - {JEDEC_RDSR, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read Device Status Reg - {JEDEC_REMS, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Read Electronic Manufacturer Signature - {JEDEC_WRSR, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 0}, // Write Status Register - {JEDEC_RDID, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read JDEC ID - {JEDEC_CE_C7, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 0}, // Bulk erase + {JEDEC_BYTE_PROGRAM, WRITING_OP_WITH_ADDR, 0}, // Write Byte + {JEDEC_READ, READING_OP_WITH_ADDR, 0}, // Read Data + {JEDEC_BE_D8, WRITING_OP_WITH_ADDR, 0}, // Erase Sector + {JEDEC_RDSR, READING_OP_NO_ADDR, 0}, // Read Device Status Reg + {JEDEC_REMS, READING_OP_WITH_ADDR, 0}, // Read Electronic Manufacturer Signature + {JEDEC_WRSR, WRITING_OP_NO_ADDR, 0}, // Write Status Register + {JEDEC_RDID, READING_OP_NO_ADDR, 0}, // Read JDEC ID + {JEDEC_CE_C7, WRITING_OP_NO_ADDR, 0}, // Bulk erase } };
@@ -277,17 +277,17 @@ static OPCODES O_ST_M25P = { * is needed which is currently not in the chipset OPCODE table */ static OPCODE POSSIBLE_OPCODES[] = { - {JEDEC_BYTE_PROGRAM, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 0}, // Write Byte - {JEDEC_READ, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Read Data - {JEDEC_BE_D8, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 0}, // Erase Sector - {JEDEC_RDSR, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read Device Status Reg - {JEDEC_REMS, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Read Electronic Manufacturer Signature - {JEDEC_WRSR, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 0}, // Write Status Register - {JEDEC_RDID, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read JDEC ID - {JEDEC_CE_C7, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 0}, // Bulk erase - {JEDEC_SE, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 0}, // Sector erase - {JEDEC_BE_52, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 0}, // Block erase - {JEDEC_AAI_WORD_PROGRAM, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 0}, // Auto Address Increment + {JEDEC_BYTE_PROGRAM, WRITING_OP_WITH_ADDR, 0}, // Write Byte + {JEDEC_READ, READING_OP_WITH_ADDR, 0}, // Read Data + {JEDEC_BE_D8, WRITING_OP_WITH_ADDR, 0}, // Erase Sector + {JEDEC_RDSR, READING_OP_NO_ADDR, 0}, // Read Device Status Reg + {JEDEC_REMS, READING_OP_WITH_ADDR, 0}, // Read Electronic Manufacturer Signature + {JEDEC_WRSR, WRITING_OP_NO_ADDR, 0}, // Write Status Register + {JEDEC_RDID, READING_OP_NO_ADDR, 0}, // Read JDEC ID + {JEDEC_CE_C7, WRITING_OP_NO_ADDR, 0}, // Bulk erase + {JEDEC_SE, WRITING_OP_WITH_ADDR, 0}, // Sector erase + {JEDEC_BE_52, WRITING_OP_WITH_ADDR, 0}, // Block erase + {JEDEC_AAI_WORD_PROGRAM, WRITING_OP_NO_ADDR, 0}, // Auto Address Increment };
static OPCODES O_EXISTING = {}; @@ -370,66 +370,61 @@ 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 WRITING_OP_NO_ADDR; + else if (writecnt == 1) // and readcnt is > 0 + return READING_OP_NO_ADDR; + else if (writecnt == 4) // and readcnt is > 0 + return READING_OP_WITH_ADDR; + else // we have an invalid case + return 0xFF; }
-static int reprogram_opcode_on_the_fly(uint8_t opcode, unsigned int writecnt, unsigned int readcnt) +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 + int ret; + 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; + ret = program_opcodes(curopcodes, 0); + if (ret == 0) + msg_pdbg2("OPCODE (0x%02X) re-programmed on-the-fly, op-pos=%d\n", opcode, oppos); + return ret; }
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; @@ -549,6 +544,14 @@ static int program_opcodes(OPCODES *op, int enable_undo) mmio_writew(optype, ich_spibar + ICH7_REG_OPTYPE); mmio_writel(opmenu[0], ich_spibar + ICH7_REG_OPMENU); mmio_writel(opmenu[1], ich_spibar + ICH7_REG_OPMENU + 4); + + if ((preop != mmio_readw(ich_spibar + ICH7_REG_PREOP)) || + (optype != mmio_readw(ich_spibar + ICH7_REG_OPTYPE)) || + (opmenu[0] != mmio_readl(ich_spibar + ICH7_REG_OPMENU)) || + (opmenu[1] != mmio_readl(ich_spibar + ICH7_REG_OPMENU + 4))) { + msg_perr("Programming opcodes failed.\n"); + return 1; + } break; case CHIPSET_ICH8: default: /* Future version might behave the same */ @@ -563,6 +566,13 @@ static int program_opcodes(OPCODES *op, int enable_undo) mmio_writew(optype, ich_spibar + ICH9_REG_OPTYPE); mmio_writel(opmenu[0], ich_spibar + ICH9_REG_OPMENU); mmio_writel(opmenu[1], ich_spibar + ICH9_REG_OPMENU + 4); + if ((preop != mmio_readw(ich_spibar + ICH9_REG_PREOP)) || + (optype != mmio_readw(ich_spibar + ICH9_REG_OPTYPE)) || + (opmenu[0] != mmio_readl(ich_spibar + ICH9_REG_OPMENU)) || + (opmenu[1] != mmio_readl(ich_spibar + ICH9_REG_OPMENU + 4))) { + msg_perr("Programming opcodes failed.\n"); + return 1; + } break; }
@@ -720,11 +730,11 @@ 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) - || (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) { + if ((op.spi_type == WRITING_OP_NO_ADDR) + || (op.spi_type == WRITING_OP_WITH_ADDR)) { write_cmd = 1; }
@@ -765,17 +775,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,11 +847,10 @@ 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) - || (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) { + if ((op.spi_type == WRITING_OP_NO_ADDR) || (op.spi_type == WRITING_OP_WITH_ADDR)) { write_cmd = 1; }
@@ -887,17 +896,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,86 +991,114 @@ 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) +/* Check command and prepare the appropriate opcode. + * The selected OPCODE will be returned in 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 unused. */ +static int prepare_opcode(struct flashctx *flash, unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, bool dryrun, 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}; + 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 { + if (reprogram_opcode_on_the_fly(writearr[0], spi_type, writecnt, readcnt) != 0) + return SPI_GENERIC_ERROR; + 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 * writecnt >= 4, readcnt = 0 * 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); + * writecnt >= 1 is guaranteed for all commands. */ + if ((opcode->spi_type == READING_OP_WITH_ADDR) && (writecnt != 4)) { + if (!dryrun) + msg_perr("%s: Reading command requires an opcode (0x%02x) and exactly 3 address bytes, " + "but writecnt=%i.\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 == READING_OP_NO_ADDR) && (writecnt != 1)) { + if (!dryrun) + msg_perr("%s: Reading command requires an opcode (0x%02x) without address bytes, " + "but writecnt=%i.\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 == WRITING_OP_WITH_ADDR) && (writecnt < 4)) { + if (!dryrun) + msg_perr("%s: Writing command requires at least an opcode (0x%02x) and exactly " + "3 address bytes, but writecnt=%i.\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 (((opcode->spi_type == WRITING_OP_WITH_ADDR) || (opcode->spi_type == WRITING_OP_NO_ADDR)) && + (readcnt > 0)) { + if (!dryrun) + msg_perr("%s: Writing command with opcode (0x%02x) can read not bytes, " + "but readcnt=%i.\n", __func__, writearr[0], readcnt); return SPI_INVALID_LENGTH; }
- /* if opcode-type requires an address */ - 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); + /* If the opcode type requires an address we check if it is below the allowed base. */ + if (opcode->spi_type == READING_OP_WITH_ADDR || opcode->spi_type == WRITING_OP_WITH_ADDR) { + 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, false, &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 @@ -1069,10 +1106,10 @@ static int ich_spi_send_command(struct flashctx *flash, unsigned int writecnt, * and are thus not counted towards data length. The only exception * applies if the opcode definition (un)intentionally classifies said * opcode incorrectly as non-address opcode or vice versa. */ - if (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS) { + if (opcode->spi_type == WRITING_OP_NO_ADDR) { data = (uint8_t *) (writearr + 1); count = writecnt - 1; - } else if (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) { + } else if (opcode->spi_type == WRITING_OP_WITH_ADDR) { data = (uint8_t *) (writearr + 4); count = writecnt - 4; } else { @@ -1080,11 +1117,11 @@ 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); - if ((opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) || - (opcode->spi_type == SPI_OPCODE_TYPE_READ_WITH_ADDRESS)) { + if ((opcode->spi_type == WRITING_OP_WITH_ADDR) || (opcode->spi_type == READING_OP_WITH_ADDR)) { msg_pdbg("at address 0x%06x ", addr); } msg_pdbg("(payload length was %d).\n", count); @@ -1092,8 +1129,7 @@ static int ich_spi_send_command(struct flashctx *flash, unsigned int writecnt, /* Print out the data array if it contains data to write. * Errors are detected before the received data is read back into * the array so it won't make sense to print it then. */ - if ((opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) || - (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)) { + if ((opcode->spi_type == WRITING_OP_WITH_ADDR) || (opcode->spi_type == WRITING_OP_NO_ADDR)) { int i; msg_pspew("The data was:\n"); for (i = 0; i < count; i++){ @@ -1358,17 +1394,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 +1412,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 +1423,19 @@ 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; + } + ret = reprogram_opcode_on_the_fly(cmd_nxt->writearr[0], spi_type, + cmd_nxt->writecnt, cmd_nxt->readcnt); + if (ret == -1) + continue; + oppos = find_opcode(curopcodes, cmd_nxt->writearr[0]); if (oppos == -1) continue; curopcodes->opcode[oppos].atomic = preoppos + 1; @@ -1793,10 +1838,8 @@ int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb, } }
- if (ich_spi_mode == ich_auto && ichspi_lock && - ich_missing_opcodes()) { - msg_pinfo("Enabling hardware sequencing because " - "some important opcode is locked.\n"); + if (ich_spi_mode == ich_auto && ichspi_lock && ich_missing_opcodes()) { + msg_pinfo("Enabling hardware sequencing because an important opcode is unavailable.\n"); ich_spi_mode = ich_hwseq; }