From a57258e9b18f2f336457165391572bc477371e94 Mon Sep 17 00:00:00 2001 From: Mahantesh Kumbar Date: Thu, 7 Dec 2017 22:08:10 +0530 Subject: gpu: nvgpu: RPC interface support - Created nv_pmu_rpc_cmd & nv_pmu_rpc_msg struct, & added member rpc under pmu_cmd & pmu_msg - Created RPC header interface - Created RPC desc struct & added as member to pmu payload - Defined PMU_RPC_EXECUTE() to convert different RPC request to make generic RPC call. - nvgpu_pmu_rpc_execute() function to execute RPC request by creating required RPC payload & send request to PMU to execute. - nvgpu_pmu_rpc_execute() function as default callback handler for RPC if caller not provided callback - Modified nvgpu_pmu_rpc_execute() function to include check of RPC payload parameter. - Modified nvgpu_pmu_cmd_post() function to handle RPC payload request. JIRA GPUT19X-137 Change-Id: Iac140eb6b98d6bae06a089e71c96f15068fe7e7b Signed-off-by: Mahantesh Kumbar Signed-off-by: seshendra Gadagottu Reviewed-on: https://git-master.nvidia.com/r/1613266 Reviewed-by: svc-mobile-coverity GVS: Gerrit_Virtual_Submit Tested-by: Deepak Goyal Reviewed-by: Vijayakumar Subbu Reviewed-by: mobile promotions Tested-by: mobile promotions --- drivers/gpu/nvgpu/common/pmu/pmu_ipc.c | 238 +++++++++++++++++---- drivers/gpu/nvgpu/include/nvgpu/pmu.h | 25 +++ drivers/gpu/nvgpu/include/nvgpu/pmuif/gpmuif_cmn.h | 18 ++ .../nvgpu/include/nvgpu/pmuif/nvgpu_gpmu_cmdif.h | 43 ++++ 4 files changed, 282 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/nvgpu/common/pmu/pmu_ipc.c b/drivers/gpu/nvgpu/common/pmu/pmu_ipc.c index 4c706e57..829fee19 100644 --- a/drivers/gpu/nvgpu/common/pmu/pmu_ipc.c +++ b/drivers/gpu/nvgpu/common/pmu/pmu_ipc.c @@ -410,11 +410,13 @@ static bool pmu_validate_cmd(struct nvgpu_pmu *pmu, struct pmu_cmd *cmd, if (payload == NULL) return true; - if (payload->in.buf == NULL && payload->out.buf == NULL) + if (payload->in.buf == NULL && payload->out.buf == NULL && + payload->rpc.prpc == NULL) goto invalid_cmd; if ((payload->in.buf != NULL && payload->in.size == 0) || - (payload->out.buf != NULL && payload->out.size == 0)) + (payload->out.buf != NULL && payload->out.size == 0) || + (payload->rpc.prpc != NULL && payload->rpc.size_rpc == 0)) goto invalid_cmd; in_size = PMU_CMD_HDR_SIZE; @@ -491,55 +493,61 @@ clean_up: return err; } -int nvgpu_pmu_cmd_post(struct gk20a *g, struct pmu_cmd *cmd, - struct pmu_msg *msg, struct pmu_payload *payload, - u32 queue_id, pmu_callback callback, void *cb_param, - u32 *seq_desc, unsigned long timeout) +static int pmu_cmd_payload_extract_rpc(struct gk20a *g, struct pmu_cmd *cmd, + struct pmu_payload *payload, struct pmu_sequence *seq) { struct nvgpu_pmu *pmu = &g->pmu; struct pmu_v *pv = &g->ops.pmu_ver; - struct pmu_sequence *seq; - void *in = NULL, *out = NULL; - int err; + u16 dmem_alloc_size = 0; + u32 dmem_alloc_offset = 0; + int err = 0; nvgpu_log_fn(g, " "); - if ((!cmd) || (!seq_desc) || (!pmu->pmu_ready)) { - if (!cmd) - nvgpu_warn(g, "%s(): PMU cmd buffer is NULL", __func__); - else if (!seq_desc) - nvgpu_warn(g, "%s(): Seq descriptor is NULL", __func__); - else - nvgpu_warn(g, "%s(): PMU is not ready", __func__); - - WARN_ON(1); - return -EINVAL; + dmem_alloc_size = payload->rpc.size_rpc + + payload->rpc.size_scratch; + dmem_alloc_offset = nvgpu_alloc(&pmu->dmem, dmem_alloc_size); + if (!dmem_alloc_offset) { + err = -ENOMEM; + goto clean_up; } - if (!pmu_validate_cmd(pmu, cmd, msg, payload, queue_id)) - return -EINVAL; + nvgpu_flcn_copy_to_dmem(pmu->flcn, dmem_alloc_offset, + payload->rpc.prpc, payload->rpc.size_rpc, 0); - err = pmu_seq_acquire(pmu, &seq); + cmd->cmd.rpc.rpc_dmem_size = payload->rpc.size_rpc; + cmd->cmd.rpc.rpc_dmem_ptr = dmem_alloc_offset; + + seq->out_payload = payload->rpc.prpc; + pv->pmu_allocation_set_dmem_size(pmu, + pv->get_pmu_seq_out_a_ptr(seq), + payload->rpc.size_rpc); + pv->pmu_allocation_set_dmem_offset(pmu, + pv->get_pmu_seq_out_a_ptr(seq), + dmem_alloc_offset); + +clean_up: if (err) - return err; + nvgpu_log_fn(g, "fail"); + else + nvgpu_log_fn(g, "done"); - cmd->hdr.seq_id = seq->id; + return err; +} - cmd->hdr.ctrl_flags = 0; - cmd->hdr.ctrl_flags |= PMU_CMD_FLAGS_STATUS; - cmd->hdr.ctrl_flags |= PMU_CMD_FLAGS_INTR; +static int pmu_cmd_payload_extract(struct gk20a *g, struct pmu_cmd *cmd, + struct pmu_payload *payload, struct pmu_sequence *seq) +{ + struct nvgpu_pmu *pmu = &g->pmu; + struct pmu_v *pv = &g->ops.pmu_ver; + void *in = NULL, *out = NULL; + int err = 0; - seq->callback = callback; - seq->cb_params = cb_param; - seq->msg = msg; - seq->out_payload = NULL; - seq->desc = pmu->next_seq_desc++; + nvgpu_log_fn(g, " "); if (payload) seq->out_payload = payload->out.buf; - *seq_desc = seq->desc; - if (payload && payload->in.offset != 0) { pv->set_pmu_allocation_ptr(pmu, &in, ((u8 *)&cmd->cmd + payload->in.offset)); @@ -553,7 +561,7 @@ int nvgpu_pmu_cmd_post(struct gk20a *g, struct pmu_cmd *cmd, *(pv->pmu_allocation_get_dmem_offset_addr(pmu, in)) = nvgpu_alloc(&pmu->dmem, - pv->pmu_allocation_get_dmem_size(pmu, in)); + pv->pmu_allocation_get_dmem_size(pmu, in)); if (!*(pv->pmu_allocation_get_dmem_offset_addr(pmu, in))) goto clean_up; @@ -596,7 +604,8 @@ int nvgpu_pmu_cmd_post(struct gk20a *g, struct pmu_cmd *cmd, if (payload->in.buf != payload->out.buf) { *(pv->pmu_allocation_get_dmem_offset_addr(pmu, out)) = nvgpu_alloc(&pmu->dmem, - pv->pmu_allocation_get_dmem_size(pmu, out)); + pv->pmu_allocation_get_dmem_size(pmu, + out)); if (!*(pv->pmu_allocation_get_dmem_offset_addr(pmu, out))) goto clean_up; @@ -630,7 +639,72 @@ int nvgpu_pmu_cmd_post(struct gk20a *g, struct pmu_cmd *cmd, } +clean_up: + if (err) { + nvgpu_log_fn(g, "fail"); + if (in) + nvgpu_free(&pmu->dmem, + pv->pmu_allocation_get_dmem_offset(pmu, in)); + if (out) + nvgpu_free(&pmu->dmem, + pv->pmu_allocation_get_dmem_offset(pmu, out)); + } else + nvgpu_log_fn(g, "done"); + + return err; +} + +int nvgpu_pmu_cmd_post(struct gk20a *g, struct pmu_cmd *cmd, + struct pmu_msg *msg, struct pmu_payload *payload, + u32 queue_id, pmu_callback callback, void *cb_param, + u32 *seq_desc, unsigned long timeout) +{ + struct nvgpu_pmu *pmu = &g->pmu; + struct pmu_sequence *seq; + int err; + + nvgpu_log_fn(g, " "); + + if ((!cmd) || (!seq_desc) || (!pmu->pmu_ready)) { + if (!cmd) + nvgpu_warn(g, "%s(): PMU cmd buffer is NULL", __func__); + else if (!seq_desc) + nvgpu_warn(g, "%s(): Seq descriptor is NULL", __func__); + else + nvgpu_warn(g, "%s(): PMU is not ready", __func__); + + WARN_ON(1); + return -EINVAL; + } + + if (!pmu_validate_cmd(pmu, cmd, msg, payload, queue_id)) + return -EINVAL; + err = pmu_seq_acquire(pmu, &seq); + if (err) + return err; + + cmd->hdr.seq_id = seq->id; + + cmd->hdr.ctrl_flags = 0; + cmd->hdr.ctrl_flags |= PMU_CMD_FLAGS_STATUS; + cmd->hdr.ctrl_flags |= PMU_CMD_FLAGS_INTR; + + seq->callback = callback; + seq->cb_params = cb_param; + seq->msg = msg; + seq->out_payload = NULL; + seq->desc = pmu->next_seq_desc++; + + *seq_desc = seq->desc; + + if (cmd->cmd.rpc.cmd_type == NV_PMU_RPC_CMD_ID) + err = pmu_cmd_payload_extract_rpc(g, cmd, payload, seq); + else + err = pmu_cmd_payload_extract(g, cmd, payload, seq); + + if (err) + goto clean_up; seq->state = PMU_SEQ_STATE_USED; @@ -644,12 +718,6 @@ int nvgpu_pmu_cmd_post(struct gk20a *g, struct pmu_cmd *cmd, clean_up: nvgpu_log_fn(g, "fail"); - if (in) - nvgpu_free(&pmu->dmem, - pv->pmu_allocation_get_dmem_offset(pmu, in)); - if (out) - nvgpu_free(&pmu->dmem, - pv->pmu_allocation_get_dmem_offset(pmu, out)); pmu_seq_release(pmu, seq); return err; @@ -666,6 +734,7 @@ static int pmu_response_handle(struct nvgpu_pmu *pmu, nvgpu_log_fn(g, " "); seq = &pmu->seq[msg->hdr.seq_id]; + if (seq->state != PMU_SEQ_STATE_USED && seq->state != PMU_SEQ_STATE_CANCELLED) { nvgpu_err(g, "msg for an unknown sequence %d", seq->id); @@ -905,3 +974,88 @@ int pmu_wait_message_cond(struct nvgpu_pmu *pmu, u32 timeout_ms, return -ETIMEDOUT; } +static void pmu_rpc_handler(struct gk20a *g, struct pmu_msg *msg, + void *param, u32 handle, u32 status) +{ + struct nv_pmu_rpc_header rpc; + + memset(&rpc, 0, sizeof(struct nv_pmu_rpc_header)); + if (param) + memcpy(&rpc, param, sizeof(struct nv_pmu_rpc_header)); + + if (rpc.flcn_status) { + nvgpu_err(g, " failed RPC response, status=0x%x, func=0x%x", + rpc.flcn_status, rpc.function); + goto exit; + } + + switch (msg->hdr.unit_id) { + /* TBD case will be added */ + default: + nvgpu_err(g, " Invalid RPC response, stats 0x%x", + rpc.flcn_status); + break; + } + +exit: + /* free allocated memory */ + if (param) + nvgpu_kfree(g, param); +} + +int nvgpu_pmu_rpc_execute(struct nvgpu_pmu *pmu, struct nv_pmu_rpc_header *rpc, + u16 size_rpc, u16 size_scratch, pmu_callback caller_cb, + void *caller_cb_param) +{ + struct gk20a *g = pmu->g; + struct pmu_cmd cmd; + struct pmu_payload payload; + pmu_callback callback = caller_cb; + void *rpc_buff = NULL; + void *cb_param = caller_cb_param; + u32 seq = 0; + int status = 0; + + if (!pmu->pmu_ready) { + nvgpu_warn(g, "PMU is not ready to process RPC"); + return -EINVAL; + } + + rpc_buff = nvgpu_kzalloc(g, size_rpc); + if (!rpc_buff) + return -ENOMEM; + + memset(&cmd, 0, sizeof(struct pmu_cmd)); + memset(&payload, 0, sizeof(struct pmu_payload)); + + cmd.hdr.unit_id = rpc->unit_id; + cmd.hdr.size = PMU_CMD_HDR_SIZE + sizeof(struct nv_pmu_rpc_cmd); + cmd.cmd.rpc.cmd_type = NV_PMU_RPC_CMD_ID; + cmd.cmd.rpc.flags = rpc->flags; + + memcpy(rpc_buff, rpc, size_rpc); + payload.rpc.prpc = rpc_buff; + payload.rpc.size_rpc = size_rpc; + payload.rpc.size_scratch = size_scratch; + + /* assign default RPC handler & buffer */ + if (!callback && !cb_param) { + callback = pmu_rpc_handler; + cb_param = rpc_buff; + } + + status = nvgpu_pmu_cmd_post(g, &cmd, NULL, &payload, + PMU_COMMAND_QUEUE_LPQ, pmu_rpc_handler, + cb_param, &seq, ~0); + if (status) { + nvgpu_err(g, "Failed to execute RPC status=0x%x, func=0x%x", + status, rpc->function); + } + + /* if caller passed buff then free allocated RPC buffer */ + if (caller_cb_param) + nvgpu_kfree(g, rpc_buff); + + return status; + +} diff --git a/drivers/gpu/nvgpu/include/nvgpu/pmu.h b/drivers/gpu/nvgpu/include/nvgpu/pmu.h index c0ceca61..cd7e1879 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/pmu.h +++ b/drivers/gpu/nvgpu/include/nvgpu/pmu.h @@ -143,9 +143,29 @@ enum { #define APCTRL_POWER_BREAKEVEN_DEFAULT_US (2000) #define APCTRL_CYCLES_PER_SAMPLE_MAX_DEFAULT (200) +/* RPC */ +#define PMU_RPC_EXECUTE(_stat, _pmu, _unit, _func, _prpc, _size)\ + do { \ + memset(&((_prpc)->hdr), 0, sizeof((_prpc)->hdr));\ + \ + (_prpc)->hdr.unit_id = PMU_UNIT_##_unit; \ + (_prpc)->hdr.function = NV_PMU_RPC_ID_##_unit##_##_func;\ + (_prpc)->hdr.flags = 0x0; \ + \ + _stat = nvgpu_pmu_rpc_execute(_pmu, &((_prpc)->hdr), \ + (sizeof(*(_prpc)) - sizeof((_prpc)->scratch)),\ + (_size), NULL, NULL); \ + } while (0) + typedef void (*pmu_callback)(struct gk20a *, struct pmu_msg *, void *, u32, u32); +struct pmu_rpc_desc { + void *prpc; + u16 size_rpc; + u16 size_scratch; +}; + struct pmu_payload { struct { void *buf; @@ -153,6 +173,7 @@ struct pmu_payload { u32 size; u32 fb_size; } in, out; + struct pmu_rpc_desc rpc; }; struct pmu_ucode_desc { @@ -472,4 +493,8 @@ void nvgpu_pmu_dump_falcon_stats(struct nvgpu_pmu *pmu); void nvgpu_pmu_dump_elpg_stats(struct nvgpu_pmu *pmu); bool nvgpu_find_hex_in_string(char *strings, struct gk20a *g, u32 *hex_pos); +/* PMU RPC */ +int nvgpu_pmu_rpc_execute(struct nvgpu_pmu *pmu, struct nv_pmu_rpc_header *rpc, + u16 size_rpc, u16 size_scratch, pmu_callback callback, void *cb_param); + #endif /* __NVGPU_PMU_H__ */ diff --git a/drivers/gpu/nvgpu/include/nvgpu/pmuif/gpmuif_cmn.h b/drivers/gpu/nvgpu/include/nvgpu/pmuif/gpmuif_cmn.h index f39e7b6c..2284289e 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/pmuif/gpmuif_cmn.h +++ b/drivers/gpu/nvgpu/include/nvgpu/pmuif/gpmuif_cmn.h @@ -127,4 +127,22 @@ union name##_aligned { \ (PMU_FB_COPY_RW_ALIGNMENT))]; \ } +/* RPC (Remote Procedure Call) header structure */ +#define NV_PMU_RPC_FLAGS_TYPE_SYNC 0x00000000 + +struct nv_pmu_rpc_header { + /* Identifies the unit servicing requested RPC*/ + u8 unit_id; + /* Identifies the requested RPC (within the unit)*/ + u8 function; + /* RPC call flags (@see PMU_RPC_FLAGS) */ + u8 flags; + /* Falcon's status code to describe failures*/ + u8 flcn_status; + /* RPC's total exec. time (measured on nvgpu driver side)*/ + u32 exec_time_nv_ns; + /* RPC's actual exec. time (measured on PMU side)*/ + u32 exec_time_pmu_ns; +}; + #endif /* _GPMUIFCMN_H_*/ diff --git a/drivers/gpu/nvgpu/include/nvgpu/pmuif/nvgpu_gpmu_cmdif.h b/drivers/gpu/nvgpu/include/nvgpu/pmuif/nvgpu_gpmu_cmdif.h index fea6326a..208644d7 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/pmuif/nvgpu_gpmu_cmdif.h +++ b/drivers/gpu/nvgpu/include/nvgpu/pmuif/nvgpu_gpmu_cmdif.h @@ -39,6 +39,47 @@ #include "gpmuifthermsensor.h" #include "gpmuifseq.h" +/* + * Command requesting execution of the RPC (Remote Procedure Call) + */ +struct nv_pmu_rpc_cmd { + /* Must be set to @ref NV_PMU_RPC_CMD_ID */ + u8 cmd_type; + /* RPC call flags (@see PMU_RPC_FLAGS) */ + u8 flags; + /* Size of RPC structure allocated + * within NV managed DMEM heap + */ + u16 rpc_dmem_size; + /* + * DMEM pointer of RPC structure allocated + * within RM managed DMEM heap. + */ + u32 rpc_dmem_ptr; +}; + +#define NV_PMU_RPC_CMD_ID 0x80 + +/* Message carrying the result of the RPC execution */ +struct nv_pmu_rpc_msg { + /* Must be set to @ref NV_PMU_RPC_MSG_ID */ + u8 msg_type; + /* RPC call flags (@see PMU_RPC_FLAGS)*/ + u8 flags; + /* + * Size of RPC structure allocated + * within NV managed DMEM heap. + */ + u16 rpc_dmem_size; + /* + * DMEM pointer of RPC structure allocated + * within NV managed DMEM heap. + */ + u32 rpc_dmem_ptr; +}; + +#define NV_PMU_RPC_MSG_ID 0x80 + struct pmu_cmd { struct pmu_hdr hdr; union { @@ -52,6 +93,7 @@ struct pmu_cmd { struct nv_pmu_clk_cmd clk; struct nv_pmu_pmgr_cmd pmgr; struct nv_pmu_therm_cmd therm; + struct nv_pmu_rpc_cmd rpc; } cmd; }; @@ -69,6 +111,7 @@ struct pmu_msg { struct nv_pmu_clk_msg clk; struct nv_pmu_pmgr_msg pmgr; struct nv_pmu_therm_msg therm; + struct nv_pmu_rpc_msg rpc; } msg; }; -- cgit v1.2.2