summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/soc/intel/common/block/cse/cse.c128
1 files changed, 74 insertions, 54 deletions
diff --git a/src/soc/intel/common/block/cse/cse.c b/src/soc/intel/common/block/cse/cse.c
index 53c4a81959..167cccd1ae 100644
--- a/src/soc/intel/common/block/cse/cse.c
+++ b/src/soc/intel/common/block/cse/cse.c
@@ -27,6 +27,8 @@
#include <string.h>
#include <timer.h>
+#define MAX_HECI_MESSAGE_RETRY_COUNT 5
+
/* Wait up to 15 sec for HECI to get ready */
#define HECI_DELAY_READY (15 * 1000)
/* Wait up to 100 usec between circullar buffer polls */
@@ -309,45 +311,54 @@ send_one_message(uint32_t hdr, const void *buff)
int
heci_send(const void *msg, size_t len, uint8_t host_addr, uint8_t client_addr)
{
+ uint8_t retry;
uint32_t csr, hdr;
- size_t sent = 0, remaining, cb_size, max_length;
- uint8_t *p = (uint8_t *) msg;
+ size_t sent, remaining, cb_size, max_length;
+ const uint8_t *p;
if (!msg || !len)
return 0;
clear_int();
- if (!wait_heci_ready()) {
- printk(BIOS_ERR, "HECI: not ready\n");
- return 0;
- }
+ for (retry = 0; retry < MAX_HECI_MESSAGE_RETRY_COUNT; retry++) {
+ p = msg;
- csr = read_cse_csr();
- cb_size = ((csr & CSR_CBD) >> CSR_CBD_START) * SLOT_SIZE;
- /*
- * Reserve one slot for the header. Limit max message length by 9
- * bits that are available in the header.
- */
- max_length = MIN(cb_size, (1 << MEI_HDR_LENGTH_SIZE) - 1) - SLOT_SIZE;
- remaining = len;
+ if (!wait_heci_ready()) {
+ printk(BIOS_ERR, "HECI: not ready\n");
+ continue;
+ }
- /*
- * Fragment the message into smaller messages not exceeding useful
- * circullar buffer length. Mark last message complete.
- */
- do {
- hdr = MIN(max_length, remaining) << MEI_HDR_LENGTH_START;
- hdr |= client_addr << MEI_HDR_CSE_ADDR_START;
- hdr |= host_addr << MEI_HDR_HOST_ADDR_START;
- hdr |= (MIN(max_length, remaining) == remaining) ?
+ csr = read_cse_csr();
+ cb_size = ((csr & CSR_CBD) >> CSR_CBD_START) * SLOT_SIZE;
+ /*
+ * Reserve one slot for the header. Limit max message
+ * length by 9 bits that are available in the header.
+ */
+ max_length = MIN(cb_size, (1 << MEI_HDR_LENGTH_SIZE) - 1)
+ - SLOT_SIZE;
+ remaining = len;
+
+ /*
+ * Fragment the message into smaller messages not exceeding
+ * useful circullar buffer length. Mark last message complete.
+ */
+ do {
+ hdr = MIN(max_length, remaining)
+ << MEI_HDR_LENGTH_START;
+ hdr |= client_addr << MEI_HDR_CSE_ADDR_START;
+ hdr |= host_addr << MEI_HDR_HOST_ADDR_START;
+ hdr |= (MIN(max_length, remaining) == remaining) ?
MEI_HDR_IS_COMPLETE : 0;
- sent = send_one_message(hdr, p);
- p += sent;
- remaining -= sent;
- } while (remaining > 0 && sent != 0);
+ sent = send_one_message(hdr, p);
+ p += sent;
+ remaining -= sent;
+ } while (remaining > 0 && sent != 0);
- return remaining == 0;
+ if (!remaining)
+ return 1;
+ }
+ return 0;
}
static size_t
@@ -383,6 +394,13 @@ recv_one_message(uint32_t *hdr, void *buff, size_t maxlen)
i += SLOT_SIZE;
}
+ /*
+ * If ME is not ready, something went wrong and
+ * we received junk
+ */
+ if (!cse_ready())
+ return 0;
+
remainder = recv_len % SLOT_SIZE;
if (remainder) {
@@ -395,42 +413,44 @@ recv_one_message(uint32_t *hdr, void *buff, size_t maxlen)
int heci_receive(void *buff, size_t *maxlen)
{
+ uint8_t retry;
size_t left, received;
uint32_t hdr = 0;
- uint8_t *p = buff;
+ uint8_t *p;
if (!buff || !maxlen || !*maxlen)
return 0;
- left = *maxlen;
-
clear_int();
- if (!wait_heci_ready()) {
- printk(BIOS_ERR, "HECI: not ready\n");
- return 0;
- }
+ for (retry = 0; retry < MAX_HECI_MESSAGE_RETRY_COUNT; retry++) {
+ p = buff;
+ left = *maxlen;
- /*
- * Receive multiple packets until we meet one marked complete or we run
- * out of space in caller-provided buffer.
- */
- do {
- received = recv_one_message(&hdr, p, left);
- left -= received;
- p += received;
- /* If we read out everything ping to send more */
- if (!(hdr & MEI_HDR_IS_COMPLETE) && !cse_filled_slots())
- host_gen_interrupt();
- } while (received && !(hdr & MEI_HDR_IS_COMPLETE) && left > 0);
-
- *maxlen = p - (uint8_t *) buff;
-
- /* If ME is not ready, something went wrong and we received junk */
- if (!cse_ready())
- return 0;
+ if (!wait_heci_ready()) {
+ printk(BIOS_ERR, "HECI: not ready\n");
+ continue;
+ }
- return !!((hdr & MEI_HDR_IS_COMPLETE) && received);
+ /*
+ * Receive multiple packets until we meet one marked
+ * complete or we run out of space in caller-provided buffer.
+ */
+ do {
+ received = recv_one_message(&hdr, p, left);
+ left -= received;
+ p += received;
+ /* If we read out everything ping to send more */
+ if (!(hdr & MEI_HDR_IS_COMPLETE) && !cse_filled_slots())
+ host_gen_interrupt();
+ } while (received && !(hdr & MEI_HDR_IS_COMPLETE) && left > 0);
+
+ if ((hdr & MEI_HDR_IS_COMPLETE) && received) {
+ *maxlen = p - (uint8_t *) buff;
+ return 1;
+ }
+ }
+ return 0;
}
/*