[PATCH v1 0/5] SoCFPGA mailbox driver fixes and enhancements

Fixes: - Proper timeout implementation - Always read mailbox response data before returning mailbox status to caller
Enhancement: - Auto retry on mailbox sending - Send large mailbox message
Chee Hong Ang (3): arm: socfpga: mailbox: Refactor mailbox timeout event handling arm: socfpga: mailbox: Always read mailbox responses before returning status arm: socfpga: mailbox: Support sending large mailbox command
Ley Foon Tan (2): arm: socfpga: mailbox: Update mailbox response codes arm: socfpga: mailbox: Add mailbox retry support
.../mach-socfpga/include/mach/mailbox_s10.h | 38 +++- arch/arm/mach-socfpga/mailbox_s10.c | 172 ++++++++++++------ 2 files changed, 156 insertions(+), 54 deletions(-)

Add miliseconds delay when waiting for mailbox event to happen before timeout. This will ensure the timeout duration is predictive.
Signed-off-by: Chee Hong Ang chee.hong.ang@intel.com --- arch/arm/mach-socfpga/mailbox_s10.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/arch/arm/mach-socfpga/mailbox_s10.c b/arch/arm/mach-socfpga/mailbox_s10.c index f30e7f80a2..729d9b04fa 100644 --- a/arch/arm/mach-socfpga/mailbox_s10.c +++ b/arch/arm/mach-socfpga/mailbox_s10.c @@ -29,13 +29,14 @@ DECLARE_GLOBAL_DATA_PTR; static __always_inline int mbox_polling_resp(u32 rout) { u32 rin; - unsigned long i = ~0; + unsigned long i = 2000;
while (i) { rin = MBOX_READL(MBOX_RIN); if (rout != rin) return 0;
+ udelay(1000); i--; }
@@ -176,11 +177,15 @@ static __always_inline int mbox_send_cmd_common(u8 id, u32 cmd, u8 is_indirect, MBOX_WRITEL(1, MBOX_DOORBELL_TO_SDM);
while (1) { - ret = ~0; + ret = 1000;
/* Wait for doorbell from SDM */ - while (!MBOX_READL(MBOX_DOORBELL_FROM_SDM) && ret--) - ; + do { + if (MBOX_READL(MBOX_DOORBELL_FROM_SDM)) + break; + udelay(1000); + } while (--ret); + if (!ret) return -ETIMEDOUT;

-----Original Message----- From: Ang, Chee Hong chee.hong.ang@intel.com Sent: Wednesday, August 12, 2020 9:56 AM To: u-boot@lists.denx.de Cc: Marek Vasut marex@denx.de; Simon Goldschmidt simon.k.r.goldschmidt@gmail.com; Tom Rini trini@konsulko.com; See, Chin Liang chin.liang.see@intel.com; Tan, Ley Foon ley.foon.tan@intel.com; Ang, Chee Hong chee.hong.ang@intel.com; Chee, Tien Fong tien.fong.chee@intel.com; Lim, Elly Siew Chin elly.siew.chin.lim@intel.com Subject: [PATCH v1 1/5] arm: socfpga: mailbox: Refactor mailbox timeout event handling
Add miliseconds delay when waiting for mailbox event to happen before timeout. This will ensure the timeout duration is predictive.
Signed-off-by: Chee Hong Ang chee.hong.ang@intel.com
arch/arm/mach-socfpga/mailbox_s10.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/arch/arm/mach-socfpga/mailbox_s10.c b/arch/arm/mach- socfpga/mailbox_s10.c index f30e7f80a2..729d9b04fa 100644 --- a/arch/arm/mach-socfpga/mailbox_s10.c +++ b/arch/arm/mach-socfpga/mailbox_s10.c @@ -29,13 +29,14 @@ DECLARE_GLOBAL_DATA_PTR; static __always_inline int mbox_polling_resp(u32 rout) { u32 rin;
- unsigned long i = ~0;
unsigned long i = 2000;
while (i) { rin = MBOX_READL(MBOX_RIN); if (rout != rin) return 0;
udelay(1000);
i--; }
@@ -176,11 +177,15 @@ static __always_inline int mbox_send_cmd_common(u8 id, u32 cmd, u8 is_indirect, MBOX_WRITEL(1, MBOX_DOORBELL_TO_SDM);
while (1) {
ret = ~0;
ret = 1000;
/* Wait for doorbell from SDM */
while (!MBOX_READL(MBOX_DOORBELL_FROM_SDM) &&
ret--)
;
do {
if (MBOX_READL(MBOX_DOORBELL_FROM_SDM))
break;
udelay(1000);
} while (--ret);
- if (!ret) return -ETIMEDOUT;
Reviewed-by: Ley Foon Tan ley.foon.tan@intel.com

Mailbox driver should always check for the length of the response and read the response data before returning the response status to caller.
Signed-off-by: Chee Hong Ang chee.hong.ang@intel.com --- arch/arm/mach-socfpga/mailbox_s10.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/arch/arm/mach-socfpga/mailbox_s10.c b/arch/arm/mach-socfpga/mailbox_s10.c index 729d9b04fa..e8a587f007 100644 --- a/arch/arm/mach-socfpga/mailbox_s10.c +++ b/arch/arm/mach-socfpga/mailbox_s10.c @@ -221,9 +221,7 @@ static __always_inline int mbox_send_cmd_common(u8 id, u32 cmd, u8 is_indirect, if ((MBOX_RESP_CLIENT_GET(resp) == MBOX_CLIENT_ID_UBOOT) && (MBOX_RESP_ID_GET(resp) == id)) { - ret = MBOX_RESP_ERR_GET(resp); - if (ret) - return ret; + int resp_err = MBOX_RESP_ERR_GET(resp);
if (resp_buf_len) { buf_len = *resp_buf_len; @@ -252,7 +250,7 @@ static __always_inline int mbox_send_cmd_common(u8 id, u32 cmd, u8 is_indirect, buf_len--; } } - return ret; + return resp_err; } } };

-----Original Message----- From: Ang, Chee Hong chee.hong.ang@intel.com Sent: Wednesday, August 12, 2020 9:56 AM To: u-boot@lists.denx.de Cc: Marek Vasut marex@denx.de; Simon Goldschmidt simon.k.r.goldschmidt@gmail.com; Tom Rini trini@konsulko.com; See, Chin Liang chin.liang.see@intel.com; Tan, Ley Foon ley.foon.tan@intel.com; Ang, Chee Hong chee.hong.ang@intel.com; Chee, Tien Fong tien.fong.chee@intel.com; Lim, Elly Siew Chin elly.siew.chin.lim@intel.com Subject: [PATCH v1 2/5] arm: socfpga: mailbox: Always read mailbox responses before returning status
Mailbox driver should always check for the length of the response and read the response data before returning the response status to caller.
Signed-off-by: Chee Hong Ang chee.hong.ang@intel.com
arch/arm/mach-socfpga/mailbox_s10.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/arch/arm/mach-socfpga/mailbox_s10.c b/arch/arm/mach- socfpga/mailbox_s10.c index 729d9b04fa..e8a587f007 100644 --- a/arch/arm/mach-socfpga/mailbox_s10.c +++ b/arch/arm/mach-socfpga/mailbox_s10.c @@ -221,9 +221,7 @@ static __always_inline int mbox_send_cmd_common(u8 id, u32 cmd, u8 is_indirect, if ((MBOX_RESP_CLIENT_GET(resp) == MBOX_CLIENT_ID_UBOOT) && (MBOX_RESP_ID_GET(resp) == id)) {
ret = MBOX_RESP_ERR_GET(resp);
if (ret)
return ret;
int resp_err = MBOX_RESP_ERR_GET(resp); if (resp_buf_len) { buf_len = *resp_buf_len;
@@ -252,7 +250,7 @@ static __always_inline int mbox_send_cmd_common(u8 id, u32 cmd, u8 is_indirect, buf_len--; } }
return ret;
} };return resp_err; }
Reviewed-by: Ley Foon Tan ley.foon.tan@intel.com

Mailbox command which is too large to fit into the mailbox FIFO command buffer can be sent to SDM in multiple parts.
Signed-off-by: Chee Hong Ang chee.hong.ang@intel.com --- arch/arm/mach-socfpga/mailbox_s10.c | 113 +++++++++++++++++++--------- 1 file changed, 78 insertions(+), 35 deletions(-)
diff --git a/arch/arm/mach-socfpga/mailbox_s10.c b/arch/arm/mach-socfpga/mailbox_s10.c index e8a587f007..a9ec818492 100644 --- a/arch/arm/mach-socfpga/mailbox_s10.c +++ b/arch/arm/mach-socfpga/mailbox_s10.c @@ -43,41 +43,93 @@ static __always_inline int mbox_polling_resp(u32 rout) return -ETIMEDOUT; }
+static __always_inline int mbox_is_cmdbuf_full(u32 cin) +{ + return (((cin + 1) % MBOX_CMD_BUFFER_SIZE) == MBOX_READL(MBOX_COUT)); +} + +static __always_inline int mbox_is_cmdbuf_empty(u32 cin) +{ + return (((MBOX_READL(MBOX_COUT) + 1) % MBOX_CMD_BUFFER_SIZE) == cin); +} + +static __always_inline int mbox_wait_for_cmdbuf_empty(u32 cin) +{ + int timeout = 2000; + + while (timeout) { + if (mbox_is_cmdbuf_empty(cin)) + return 0; + udelay(1000); + timeout--; + } + + return -ETIMEDOUT; +} + +static __always_inline int mbox_write_cmd_buffer(u32 *cin, u32 data, + int *is_cmdbuf_overflow) +{ + int timeout = 1000; + + while (timeout) { + if (mbox_is_cmdbuf_full(*cin)) { + if (is_cmdbuf_overflow && + *is_cmdbuf_overflow == 0) { + /* Trigger SDM doorbell */ + MBOX_WRITEL(1, MBOX_DOORBELL_TO_SDM); + *is_cmdbuf_overflow = 1; + } + udelay(1000); + } else { + /* write header to circular buffer */ + MBOX_WRITE_CMD_BUF(data, (*cin)++); + *cin %= MBOX_CMD_BUFFER_SIZE; + MBOX_WRITEL(*cin, MBOX_CIN); + break; + } + timeout--; + } + + if (!timeout) + return -ETIMEDOUT; + + /* Wait for the SDM to drain the FIFO command buffer */ + if (is_cmdbuf_overflow && *is_cmdbuf_overflow) + return mbox_wait_for_cmdbuf_empty(*cin); + + return 0; +} + /* Check for available slot and write to circular buffer. * It also update command valid offset (cin) register. */ static __always_inline int mbox_fill_cmd_circular_buff(u32 header, u32 len, u32 *arg) { - u32 cin; - u32 cout; - u32 i; - - cin = MBOX_READL(MBOX_CIN) % MBOX_CMD_BUFFER_SIZE; - cout = MBOX_READL(MBOX_COUT) % MBOX_CMD_BUFFER_SIZE; + int i, ret; + int is_cmdbuf_overflow = 0; + u32 cin = MBOX_READL(MBOX_CIN) % MBOX_CMD_BUFFER_SIZE;
- /* if command buffer is full or not enough free space - * to fit the data. Note, len is in u32 unit. - */ - if (((cin + 1) % MBOX_CMD_BUFFER_SIZE) == cout || - ((MBOX_CMD_BUFFER_SIZE - cin + cout - 1) % - MBOX_CMD_BUFFER_SIZE) < (len + 1)) - return -ENOMEM; - - /* write header to circular buffer */ - MBOX_WRITE_CMD_BUF(header, cin++); - /* wrapping around when it reach the buffer size */ - cin %= MBOX_CMD_BUFFER_SIZE; + ret = mbox_write_cmd_buffer(&cin, header, &is_cmdbuf_overflow); + if (ret) + return ret;
/* write arguments */ for (i = 0; i < len; i++) { - MBOX_WRITE_CMD_BUF(arg[i], cin++); - /* wrapping around when it reach the buffer size */ - cin %= MBOX_CMD_BUFFER_SIZE; + is_cmdbuf_overflow = 0; + ret = mbox_write_cmd_buffer(&cin, arg[i], &is_cmdbuf_overflow); + if (ret) + return ret; }
- /* write command valid offset */ - MBOX_WRITEL(cin, MBOX_CIN); + /* If SDM doorbell is not triggered after the last data is + * written into mailbox FIFO command buffer, trigger the + * SDM doorbell again to ensure SDM able to read the remaining + * data. + */ + if (!is_cmdbuf_overflow) + MBOX_WRITEL(1, MBOX_DOORBELL_TO_SDM);
return 0; } @@ -90,10 +142,6 @@ static __always_inline int mbox_prepare_cmd_only(u8 id, u32 cmd, u32 header; int ret;
- /* Total length is command + argument length */ - if ((len + 1) > MBOX_CMD_BUFFER_SIZE) - return -EINVAL; - if (cmd > MBOX_MAX_CMD_INDEX) return -EINVAL;
@@ -110,11 +158,7 @@ static __always_inline int mbox_send_cmd_only_common(u8 id, u32 cmd, u8 is_indirect, u32 len, u32 *arg) { - int ret = mbox_prepare_cmd_only(id, cmd, is_indirect, len, arg); - /* write doorbell */ - MBOX_WRITEL(1, MBOX_DOORBELL_TO_SDM); - - return ret; + return mbox_prepare_cmd_only(id, cmd, is_indirect, len, arg); }
/* Return number of responses received in buffer */ @@ -167,15 +211,14 @@ static __always_inline int mbox_send_cmd_common(u8 id, u32 cmd, u8 is_indirect, status = MBOX_READL(MBOX_STATUS) & MBOX_STATUS_UA_MSK; /* Write urgent command to urgent register */ MBOX_WRITEL(cmd, MBOX_URG); + /* write doorbell */ + MBOX_WRITEL(1, MBOX_DOORBELL_TO_SDM); } else { ret = mbox_prepare_cmd_only(id, cmd, is_indirect, len, arg); if (ret) return ret; }
- /* write doorbell */ - MBOX_WRITEL(1, MBOX_DOORBELL_TO_SDM); - while (1) { ret = 1000;

-----Original Message----- From: Ang, Chee Hong chee.hong.ang@intel.com Sent: Wednesday, August 12, 2020 9:56 AM To: u-boot@lists.denx.de Cc: Marek Vasut marex@denx.de; Simon Goldschmidt simon.k.r.goldschmidt@gmail.com; Tom Rini trini@konsulko.com; See, Chin Liang chin.liang.see@intel.com; Tan, Ley Foon ley.foon.tan@intel.com; Ang, Chee Hong chee.hong.ang@intel.com; Chee, Tien Fong tien.fong.chee@intel.com; Lim, Elly Siew Chin elly.siew.chin.lim@intel.com Subject: [PATCH v1 3/5] arm: socfpga: mailbox: Support sending large mailbox command
Mailbox command which is too large to fit into the mailbox FIFO command buffer can be sent to SDM in multiple parts.
Signed-off-by: Chee Hong Ang chee.hong.ang@intel.com
Reviewed-by: Ley Foon Tan ley.foon.tan@intel.com

From: Ley Foon Tan ley.foon.tan@intel.com
Sync latest mailbox response codes from SDM firmware.
Signed-off-by: Ley Foon Tan ley.foon.tan@intel.com Signed-off-by: Chee Hong Ang chee.hong.ang@intel.com --- .../mach-socfpga/include/mach/mailbox_s10.h | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-)
diff --git a/arch/arm/mach-socfpga/include/mach/mailbox_s10.h b/arch/arm/mach-socfpga/include/mach/mailbox_s10.h index 55707ab9c5..4d783119ea 100644 --- a/arch/arm/mach-socfpga/include/mach/mailbox_s10.h +++ b/arch/arm/mach-socfpga/include/mach/mailbox_s10.h @@ -67,8 +67,42 @@ enum ALT_SDM_MBOX_RESP_CODE { MBOX_RESP_UNKNOWN_BR = 2, /* CMD code not recognized by firmware */ MBOX_RESP_UNKNOWN = 3, - /* Indicates that the device is not configured */ - MBOX_RESP_NOT_CONFIGURED = 256, + /* Length setting is not a valid length for this CMD type */ + MBOX_RESP_INVALID_LEN = 4, + /* Indirect setting is not valid for this CMD type */ + MBOX_RESP_INVALID_INDIRECT_SETTING = 5, + /* HW source which is not allowed to send CMD type */ + MBOX_RESP_CMD_INVALID_ON_SRC = 6, + /* Client with ID not associated with any running PR CMD tries to run + * RECONFIG_DATA RECONFIG_STATUS and accessing QSPI / SDMMC using ID + * without exclusive access + */ + MBOX_RESP_CLIENT_ID_NO_MATCH = 8, + /* Address provided to the system is invalid (alignment, range + * permission) + */ + MBOX_RESP_INVALID_ADDR = 0x9, + /* Signature authentication failed */ + MBOX_RESP_AUTH_FAIL = 0xA, + /* CMD timed out */ + MBOX_RESP_TIMEOUT = 0xB, + /* HW (i.e. QSPI) is not ready (initialized or configured) */ + MBOX_RESP_HW_NOT_RDY = 0xC, + /* Invalid license for IID registration */ + MBOX_RESP_PUF_ACCCES_FAILED = 0x80, + MBOX_PUF_ENROLL_DISABLE = 0x81, + MBOX_RESP_PUF_ENROLL_FAIL = 0x82, + MBOX_RESP_PUF_RAM_TEST_FAIL = 0x83, + MBOX_RESP_ATTEST_CERT_GEN_FAIL = 0x84, + /* Operation not allowed under current security settings */ + MBOX_RESP_NOT_ALLOWED_UNDER_SECURITY_SETTINGS = 0x85, + MBOX_RESP_PUF_TRNG_FAIL = 0x86, + MBOX_RESP_FUSE_ALREADY_BLOWN = 0x87, + MBOX_RESP_INVALID_SIGNATURE = 0x88, + MBOX_RESP_INVALID_HASH = 0x8b, + MBOX_RESP_INVALID_CERTIFICATE = 0x91, + /* Indicates that the device (FPGA or HPS) is not configured */ + MBOX_RESP_NOT_CONFIGURED = 0x100, /* Indicates that the device is busy */ MBOX_RESP_DEVICE_BUSY = 0x1FF, /* Indicates that there is no valid response available */

From: Ley Foon Tan ley.foon.tan@intel.com
Resend mailbox command for 3 times with 2ms interval in between if it receives MBOX_RESP_TIMEOUT and MBOX_RESP_DEVICE_BUSY response code.
Add a wrapper function mbox_send_cmd_common_retry() for retry, change all the callers to use this wrapper function.
Signed-off-by: Ley Foon Tan ley.foon.tan@intel.com Signed-off-by: Chee Hong Ang chee.hong.ang@intel.com --- arch/arm/mach-socfpga/mailbox_s10.c | 40 ++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 9 deletions(-)
diff --git a/arch/arm/mach-socfpga/mailbox_s10.c b/arch/arm/mach-socfpga/mailbox_s10.c index a9ec818492..18d44924e6 100644 --- a/arch/arm/mach-socfpga/mailbox_s10.c +++ b/arch/arm/mach-socfpga/mailbox_s10.c @@ -296,11 +296,33 @@ static __always_inline int mbox_send_cmd_common(u8 id, u32 cmd, u8 is_indirect, return resp_err; } } - }; + }
return -EIO; }
+static __always_inline int mbox_send_cmd_common_retry(u8 id, u32 cmd, + u8 is_indirect, + u32 len, u32 *arg, + u8 urgent, + u32 *resp_buf_len, + u32 *resp_buf) +{ + int ret; + int i; + + for (i = 0; i < 3; i++) { + ret = mbox_send_cmd_common(id, cmd, is_indirect, len, arg, + urgent, resp_buf_len, resp_buf); + if (ret == MBOX_RESP_TIMEOUT || ret == MBOX_RESP_DEVICE_BUSY) + udelay(2000); /* wait for 2ms before resend */ + else + break; + } + + return ret; +} + int mbox_init(void) { int ret; @@ -395,10 +417,10 @@ static __always_inline int mbox_get_fpga_config_status_common(u32 cmd) int ret;
reconfig_status_resp_len = RECONFIG_STATUS_RESPONSE_LEN; - ret = mbox_send_cmd_common(MBOX_ID_UBOOT, cmd, - MBOX_CMD_DIRECT, 0, NULL, 0, - &reconfig_status_resp_len, - reconfig_status_resp); + ret = mbox_send_cmd_common_retry(MBOX_ID_UBOOT, cmd, + MBOX_CMD_DIRECT, 0, NULL, 0, + &reconfig_status_resp_len, + reconfig_status_resp);
if (ret) return ret; @@ -438,16 +460,16 @@ int __secure mbox_get_fpga_config_status_psci(u32 cmd) int mbox_send_cmd(u8 id, u32 cmd, u8 is_indirect, u32 len, u32 *arg, u8 urgent, u32 *resp_buf_len, u32 *resp_buf) { - return mbox_send_cmd_common(id, cmd, is_indirect, len, arg, urgent, - resp_buf_len, resp_buf); + return mbox_send_cmd_common_retry(id, cmd, is_indirect, len, arg, + urgent, resp_buf_len, resp_buf); }
int __secure mbox_send_cmd_psci(u8 id, u32 cmd, u8 is_indirect, u32 len, u32 *arg, u8 urgent, u32 *resp_buf_len, u32 *resp_buf) { - return mbox_send_cmd_common(id, cmd, is_indirect, len, arg, urgent, - resp_buf_len, resp_buf); + return mbox_send_cmd_common_retry(id, cmd, is_indirect, len, arg, + urgent, resp_buf_len, resp_buf); }
int mbox_send_cmd_only(u8 id, u32 cmd, u8 is_indirect, u32 len, u32 *arg)
participants (2)
-
Chee Hong Ang
-
Tan, Ley Foon