Several bugs were discovered in the rpmh-rsc driver which collectively meant we were never actually waiting for the TCS to flush, these were likely missed because U-Boot runs single threaded and the RPMh had typically processed the single command we sent by the time we went to send the next one. However a future patch will implement rpmh read support which requires us to properly wait for the RPMh command response so we can return the value.
Fix these issues so we correctly ensure the TCS is done before returning. Signed-off-by: Casey Connolly <[email protected]> --- drivers/soc/qcom/rpmh-rsc.c | 44 +++++++++++++++++++++++--------------------- drivers/soc/qcom/rpmh.c | 1 + 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c index f51ef0b4af9c..05fff174f832 100644 --- a/drivers/soc/qcom/rpmh-rsc.c +++ b/drivers/soc/qcom/rpmh-rsc.c @@ -283,31 +283,37 @@ static void __tcs_buffer_write(struct rsc_drv *drv, int tcs_id, int cmd_id, { u32 msgid; u32 cmd_msgid = CMD_MSGID_LEN | CMD_MSGID_WRITE; u32 cmd_enable = 0; + u32 cmd_complete = 0; struct tcs_cmd *cmd; int i, j; + if (msg->wait_for_compl) + cmd_msgid |= CMD_MSGID_RESP_REQ; + + cmd_complete = read_tcs_reg(drv, drv->regs[RSC_DRV_CMD_WAIT_FOR_CMPL], tcs_id); + for (i = 0, j = cmd_id; i < msg->num_cmds; i++, j++) { cmd = &msg->cmds[i]; cmd_enable |= BIT(j); + /* U-Boot: always wait for completion */ + cmd_complete |= (!!msg->wait_for_compl) << j; msgid = cmd_msgid; - /* - * Additionally, if the cmd->wait is set, make the command - * response reqd even if the overall request was fire-n-forget. - */ - msgid |= cmd->wait ? CMD_MSGID_RESP_REQ : 0; write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_MSGID], tcs_id, j, msgid); write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_ADDR], tcs_id, j, cmd->addr); write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_DATA], tcs_id, j, cmd->data); - debug("tcs(m): %d [%s] cmd(n): %d msgid: %#x addr: %#x data: %#x complete: %d\n", + debug("tcs(%d): [%s] cmd_id: %d: msgid: %#x addr: %#x data: %#x complete: %#x\n", tcs_id, msg->state == RPMH_ACTIVE_ONLY_STATE ? "active" : "?", j, msgid, - cmd->addr, cmd->data, cmd->wait); + cmd->addr, cmd->data, cmd_complete); } cmd_enable |= read_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id); write_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id, cmd_enable); + /* U-Boot: Tell the DRV to wait for completion (?) so we can poll on DRV_STATUS */ + /* This register applies to the entire TCS group not per command */ + write_tcs_reg(drv, drv->regs[RSC_DRV_CMD_WAIT_FOR_CMPL], tcs_id, cmd_complete); } /** * __tcs_set_trigger() - Start xfer on a TCS or unset trigger on a borrowed TCS @@ -375,28 +381,24 @@ static void __tcs_set_trigger(struct rsc_drv *drv, int tcs_id, bool trigger) */ int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg) { struct tcs_group *tcs; - int tcs_id, i; - u32 addr; + int tcs_id, i = 0; + u32 val; tcs = get_tcs_for_msg(drv, msg); if (IS_ERR(tcs)) return PTR_ERR(tcs); - /* u-boot is single-threaded, always use the first TCS as we'll never conflict */ + /* U-Boot is single-threaded, always use the first TCS as we'll never conflict */ tcs_id = tcs->offset; + if (!read_tcs_reg(drv, drv->regs[RSC_DRV_STATUS], tcs_id)) { + pr_err("%s: TCS %d is busy!\n", __func__, tcs_id); + return -EBUSY; + } tcs->req[tcs_id - tcs->offset] = msg; generic_set_bit(tcs_id, drv->tcs_in_use); - if (msg->state == RPMH_ACTIVE_ONLY_STATE && tcs->type != ACTIVE_TCS) { - /* - * Clear previously programmed WAKE commands in selected - * repurposed TCS to avoid triggering them. tcs->slots will be - * cleaned from rpmh_flush() by invoking rpmh_rsc_invalidate() - */ - write_tcs_reg_sync(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id, 0); - } /* * These two can be done after the lock is released because: * - We marked "tcs_in_use" under lock. @@ -407,12 +409,12 @@ int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg) */ __tcs_buffer_write(drv, tcs_id, 0, msg); __tcs_set_trigger(drv, tcs_id, true); - /* U-Boot: Now wait for the TCS to be cleared, indicating that we're done */ + /* U-Boot: Now wait for the TCS to be cleared, indicating that we're done. */ for (i = 0; i < USEC_PER_SEC; i++) { - addr = read_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_ADDR], i, 0); - if (addr != msg->cmds[0].addr) + val = read_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_STATUS], tcs_id, 0); + if (val & CMD_STATUS_COMPL) break; udelay(1); } diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c index 96f14a9afdf2..91b90626af36 100644 --- a/drivers/soc/qcom/rpmh.c +++ b/drivers/soc/qcom/rpmh.c @@ -21,8 +21,9 @@ .msg = { \ .state = s, \ .cmds = name.cmd, \ .num_cmds = 0, \ + .wait_for_compl = true \ }, \ .cmd = { { 0 } }, \ .dev = device, \ .needs_free = false, \ -- 2.51.0

