Skip to content

Commit 1179956

Browse files
computersforpeaceLee Jones
authored andcommitted
mfd: cros_ec: Retry commands when EC is known to be busy
Commit 001dde9 ("mfd: cros ec: spi: Fix "in progress" error signaling") pointed out some bad code, but its analysis and conclusion was not 100% correct. It *is* correct that we should not propagate result==EC_RES_IN_PROGRESS for transport errors, because this has a special meaning -- that we should follow up with EC_CMD_GET_COMMS_STATUS until the EC is no longer busy. This is definitely the wrong thing for many commands, because among other problems, EC_CMD_GET_COMMS_STATUS doesn't actually retrieve any RX data from the EC, so commands that expected some data back will instead start processing junk. For such commands, the right answer is to either propagate the error (and return that error to the caller) or resend the original command (*not* EC_CMD_GET_COMMS_STATUS). Unfortunately, commit 001dde9 forgets a crucial point: that for some long-running operations, the EC physically cannot respond to commands any more. For example, with EC_CMD_FLASH_ERASE, the EC may be re-flashing its own code regions, so it can't respond to SPI interrupts. Instead, the EC prepares us ahead of time for being busy for a "long" time, and fills its hardware buffer with EC_SPI_PAST_END. Thus, we expect to see several "transport" errors (or, messages filled with EC_SPI_PAST_END). So we should really translate that to a retryable error (-EAGAIN) and continue sending EC_CMD_GET_COMMS_STATUS until we get a ready status. IOW, it is actually important to treat some of these "junk" values as retryable errors. Together with commit 001dde9, this resolves bugs like the following: 1. EC_CMD_FLASH_ERASE now works again (with commit 001dde9, we would abort the first time we saw EC_SPI_PAST_END) 2. Before commit 001dde9, transport errors (e.g., EC_SPI_RX_BAD_DATA) seen in other commands (e.g., EC_CMD_RTC_GET_VALUE) used to yield junk data in the RX buffer; they will now yield -EAGAIN return values, and tools like 'hwclock' will simply fail instead of retrieving and re-programming undefined time values Fixes: 001dde9 ("mfd: cros ec: spi: Fix "in progress" error signaling") Signed-off-by: Brian Norris <[email protected]> Signed-off-by: Lee Jones <[email protected]>
1 parent 771c577 commit 1179956

File tree

2 files changed

+22
-4
lines changed

2 files changed

+22
-4
lines changed

drivers/mfd/cros_ec_spi.c

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -419,10 +419,25 @@ static int cros_ec_pkt_xfer_spi(struct cros_ec_device *ec_dev,
419419
/* Verify that EC can process command */
420420
for (i = 0; i < len; i++) {
421421
rx_byte = rx_buf[i];
422+
/*
423+
* Seeing the PAST_END, RX_BAD_DATA, or NOT_READY
424+
* markers are all signs that the EC didn't fully
425+
* receive our command. e.g., if the EC is flashing
426+
* itself, it can't respond to any commands and instead
427+
* clocks out EC_SPI_PAST_END from its SPI hardware
428+
* buffer. Similar occurrences can happen if the AP is
429+
* too slow to clock out data after asserting CS -- the
430+
* EC will abort and fill its buffer with
431+
* EC_SPI_RX_BAD_DATA.
432+
*
433+
* In all cases, these errors should be safe to retry.
434+
* Report -EAGAIN and let the caller decide what to do
435+
* about that.
436+
*/
422437
if (rx_byte == EC_SPI_PAST_END ||
423438
rx_byte == EC_SPI_RX_BAD_DATA ||
424439
rx_byte == EC_SPI_NOT_READY) {
425-
ret = -EREMOTEIO;
440+
ret = -EAGAIN;
426441
break;
427442
}
428443
}
@@ -431,7 +446,7 @@ static int cros_ec_pkt_xfer_spi(struct cros_ec_device *ec_dev,
431446
if (!ret)
432447
ret = cros_ec_spi_receive_packet(ec_dev,
433448
ec_msg->insize + sizeof(*response));
434-
else
449+
else if (ret != -EAGAIN)
435450
dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret);
436451

437452
final_ret = terminate_request(ec_dev);
@@ -537,10 +552,11 @@ static int cros_ec_cmd_xfer_spi(struct cros_ec_device *ec_dev,
537552
/* Verify that EC can process command */
538553
for (i = 0; i < len; i++) {
539554
rx_byte = rx_buf[i];
555+
/* See comments in cros_ec_pkt_xfer_spi() */
540556
if (rx_byte == EC_SPI_PAST_END ||
541557
rx_byte == EC_SPI_RX_BAD_DATA ||
542558
rx_byte == EC_SPI_NOT_READY) {
543-
ret = -EREMOTEIO;
559+
ret = -EAGAIN;
544560
break;
545561
}
546562
}
@@ -549,7 +565,7 @@ static int cros_ec_cmd_xfer_spi(struct cros_ec_device *ec_dev,
549565
if (!ret)
550566
ret = cros_ec_spi_receive_response(ec_dev,
551567
ec_msg->insize + EC_MSG_TX_PROTO_BYTES);
552-
else
568+
else if (ret != -EAGAIN)
553569
dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret);
554570

555571
final_ret = terminate_request(ec_dev);

drivers/platform/chrome/cros_ec_proto.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ static int send_command(struct cros_ec_device *ec_dev,
9191
usleep_range(10000, 11000);
9292

9393
ret = (*xfer_fxn)(ec_dev, status_msg);
94+
if (ret == -EAGAIN)
95+
continue;
9496
if (ret < 0)
9597
break;
9698

0 commit comments

Comments
 (0)