diff options
Diffstat (limited to 'src/soc')
-rw-r--r-- | src/soc/intel/common/block/cse/cse.c | 128 |
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; } /* |