/* * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include "gk20a/gk20a.h" #include "boardobjgrp.h" #include "ctrl/ctrlboardobj.h" #include "boardobj.h" static boardobjgrp_objinsert boardobjgrp_objinsert_final; static boardobjgrp_objgetbyidx boardobjgrp_objgetbyidx_final; static boardobjgrp_objgetnext boardobjgrp_objgetnext_final; static boardobjgrp_objremoveanddestroy boardobjgrp_objremoveanddestroy_final; static boardobjgrp_pmudatainstget boardobjgrp_pmudatainstget_stub; static boardobjgrp_pmustatusinstget boardobjgrp_pmustatusinstget_stub; static u32 boardobjgrp_pmucmdsend(struct gk20a *g, struct boardobjgrp *pboardobjgrp, struct boardobjgrp_pmu_cmd *pcmd); struct boardobjgrp_pmucmdhandler_params { /* Pointer to the BOARDOBJGRP associated with this CMD */ struct boardobjgrp *pboardobjgrp; /* Pointer to structure representing this NV_PMU_BOARDOBJ_CMD_GRP */ struct boardobjgrp_pmu_cmd *pcmd; /* Boolean indicating whether the PMU successfully handled the CMD */ u32 success; }; u32 boardobjgrp_construct_super(struct boardobjgrp *pboardobjgrp) { gk20a_dbg_info(""); if (pboardobjgrp == NULL) return -EINVAL; if (pboardobjgrp->ppobjects == NULL) return -EINVAL; if (pboardobjgrp->mask == NULL) return -EINVAL; pboardobjgrp->objmask = 0; pboardobjgrp->classid = 0; pboardobjgrp->pmu.unitid = BOARDOBJGRP_UNIT_ID_INVALID; pboardobjgrp->pmu.classid = BOARDOBJGRP_GRP_CLASS_ID_INVALID; pboardobjgrp->pmu.set.id = BOARDOBJGRP_GRP_CMD_ID_INVALID; pboardobjgrp->pmu.getstatus.id = BOARDOBJGRP_GRP_CMD_ID_INVALID; /* Initialize basic interfaces */ pboardobjgrp->destruct = boardobjgrp_destruct_super; pboardobjgrp->objinsert = boardobjgrp_objinsert_final; pboardobjgrp->objgetbyidx = boardobjgrp_objgetbyidx_final; pboardobjgrp->objgetnext = boardobjgrp_objgetnext_final; pboardobjgrp->objremoveanddestroy = boardobjgrp_objremoveanddestroy_final; pboardobjgrp->pmuinithandle = boardobjgrp_pmuinithandle_impl; pboardobjgrp->pmuhdrdatainit = boardobjgrp_pmuhdrdatainit_super; pboardobjgrp->pmudatainit = boardobjgrp_pmudatainit_super; pboardobjgrp->pmuset = boardobjgrp_pmuset_impl; pboardobjgrp->pmugetstatus = boardobjgrp_pmugetstatus_impl; pboardobjgrp->pmudatainstget = boardobjgrp_pmudatainstget_stub; pboardobjgrp->pmustatusinstget = boardobjgrp_pmustatusinstget_stub; pboardobjgrp->objmaxidx = CTRL_BOARDOBJ_IDX_INVALID; pboardobjgrp->bconstructed = true; return 0; } u32 boardobjgrp_destruct_impl(struct boardobjgrp *pboardobjgrp) { gk20a_dbg_info(""); if (pboardobjgrp == NULL) return -EINVAL; if (!pboardobjgrp->bconstructed) return 0; return pboardobjgrp->destruct(pboardobjgrp); } u32 boardobjgrp_destruct_super(struct boardobjgrp *pboardobjgrp) { struct boardobj *pboardobj; u32 status = 0; u32 stat; u8 index; gk20a_dbg_info(""); if (pboardobjgrp->mask == NULL) return -EINVAL; if (pboardobjgrp->ppobjects == NULL) return -EINVAL; BOARDOBJGRP_FOR_EACH(pboardobjgrp, struct boardobj*, pboardobj, index) { stat = pboardobjgrp->objremoveanddestroy(pboardobjgrp, index); if (status == 0) status = stat; pboardobjgrp->ppobjects[index] = NULL; pboardobjgrp->objmask &= ~BIT(index); } pboardobjgrp->objmask = 0; if (pboardobjgrp->objmaxidx != CTRL_BOARDOBJ_IDX_INVALID) { if (status == 0) status = -EINVAL; WARN_ON(true); } /* Destroy the PMU CMD data */ stat = boardobjgrp_pmucmd_destroy_impl(&pboardobjgrp->pmu.set); if (status == 0) status = stat; stat = boardobjgrp_pmucmd_destroy_impl(&pboardobjgrp->pmu.getstatus); if (status == 0) status = stat; pboardobjgrp->bconstructed = false; return status; } u32 boardobjgrp_pmucmd_construct_impl(struct gk20a *g, struct boardobjgrp *pboardobjgrp, struct boardobjgrp_pmu_cmd *cmd, u8 id, u8 msgid, u8 hdrsize, u8 entrysize, u16 fbsize) { gk20a_dbg_info(""); /* Copy the parameters into the CMD*/ cmd->id = id; cmd->msgid = msgid; cmd->hdrsize = hdrsize; cmd->entrysize = entrysize; cmd->fbsize = fbsize; return 0; } u32 boardobjgrp_pmucmd_destroy_impl(struct boardobjgrp_pmu_cmd *cmd) { return 0; } u32 boardobjgrp_pmucmd_pmuinithandle_impl(struct gk20a *g, struct boardobjgrp *pboardobjgrp, struct boardobjgrp_pmu_cmd *pcmd) { u32 status = 0; struct nvgpu_mem *sysmem_desc = &pcmd->surf.sysmem_desc; gk20a_dbg_info(""); if (pcmd->id == BOARDOBJGRP_GRP_CMD_ID_INVALID) goto boardobjgrp_pmucmd_pmuinithandle_exit; nvgpu_pmu_sysmem_surface_alloc(g, sysmem_desc, pcmd->fbsize); /* we only have got sysmem later this will get copied to vidmem surface*/ pcmd->surf.vidmem_desc.size = 0; pcmd->buf = (struct nv_pmu_boardobjgrp_super *)sysmem_desc->cpu_va; boardobjgrp_pmucmd_pmuinithandle_exit: return status; } u32 boardobjgrp_pmuinithandle_impl(struct gk20a *g, struct boardobjgrp *pboardobjgrp) { u32 status = 0; gk20a_dbg_info(""); status = boardobjgrp_pmucmd_pmuinithandle_impl(g, pboardobjgrp, &pboardobjgrp->pmu.set); if (status) { nvgpu_err(g, "failed to init pmu set cmd"); goto boardobjgrp_pmuinithandle_exit; } status = boardobjgrp_pmucmd_pmuinithandle_impl(g, pboardobjgrp, &pboardobjgrp->pmu.getstatus); if (status) { nvgpu_err(g, "failed to init get status command"); goto boardobjgrp_pmuinithandle_exit; } /* If the GRP_SET CMD has not been allocated, nothing left to do. */ if (((pboardobjgrp->pmu.set.id) == BOARDOBJGRP_GRP_CMD_ID_INVALID) || (BOARDOBJGRP_IS_EMPTY(pboardobjgrp))) goto boardobjgrp_pmuinithandle_exit; /* Send the BOARDOBJGRP to the pmu via RM_PMU_BOARDOBJ_CMD_GRP. */ status = pboardobjgrp->pmuset(g, pboardobjgrp); if (status) nvgpu_err(g, "failed to send boardobg grp to PMU"); boardobjgrp_pmuinithandle_exit: return status; } u32 boardobjgrp_pmuhdrdatainit_super(struct gk20a *g, struct boardobjgrp *pboardobjgrp, struct nv_pmu_boardobjgrp_super *pboardobjgrppmu, struct boardobjgrpmask *mask) { gk20a_dbg_info(""); if (pboardobjgrp == NULL) return -EINVAL; if (pboardobjgrppmu == NULL) return -EINVAL; pboardobjgrppmu->type = pboardobjgrp->type; pboardobjgrppmu->class_id = pboardobjgrp->classid; pboardobjgrppmu->obj_slots = BOARDOBJGRP_PMU_SLOTS_GET(pboardobjgrp); gk20a_dbg_info(" Done"); return 0; } static u32 boardobjgrp_pmudatainstget_stub(struct gk20a *g, struct nv_pmu_boardobjgrp *boardobjgrppmu, struct nv_pmu_boardobj **ppboardobjpmudata, u8 idx) { gk20a_dbg_info(""); return -EINVAL; } static u32 boardobjgrp_pmustatusinstget_stub(struct gk20a *g, void *pboardobjgrppmu, struct nv_pmu_boardobj_query **ppBoardobjpmustatus, u8 idx) { gk20a_dbg_info(""); return -EINVAL; } u32 boardobjgrp_pmudatainit_legacy(struct gk20a *g, struct boardobjgrp *pboardobjgrp, struct nv_pmu_boardobjgrp_super *pboardobjgrppmu) { u32 status = 0; struct boardobj *pboardobj = NULL; struct nv_pmu_boardobj *ppmudata = NULL; u8 index; gk20a_dbg_info(""); if (pboardobjgrp == NULL) return -EINVAL; if (pboardobjgrppmu == NULL) return -EINVAL; boardobjgrpe32hdrset((struct nv_pmu_boardobjgrp *)pboardobjgrppmu, pboardobjgrp->objmask); BOARDOBJGRP_FOR_EACH_INDEX_IN_MASK(32, index, pboardobjgrp->objmask) { /* Obtain pointer to the current instance of the Object from the Group */ pboardobj = pboardobjgrp->objgetbyidx(pboardobjgrp, index); if (NULL == pboardobj) { nvgpu_err(g, "could not get object instance"); status = -EINVAL; goto boardobjgrppmudatainit_legacy_done; } status = pboardobjgrp->pmudatainstget(g, (struct nv_pmu_boardobjgrp *)pboardobjgrppmu, &ppmudata, index); if (status) { nvgpu_err(g, "could not get object instance"); goto boardobjgrppmudatainit_legacy_done; } /* Initialize the PMU Data */ status = pboardobj->pmudatainit(g, pboardobj, ppmudata); if (status) { nvgpu_err(g, "could not parse pmu for device %d", index); goto boardobjgrppmudatainit_legacy_done; } } BOARDOBJGRP_FOR_EACH_INDEX_IN_MASK_END boardobjgrppmudatainit_legacy_done: gk20a_dbg_info(" Done"); return status; } u32 boardobjgrp_pmudatainit_super(struct gk20a *g, struct boardobjgrp *pboardobjgrp, struct nv_pmu_boardobjgrp_super *pboardobjgrppmu) { u32 status = 0; struct boardobj *pboardobj = NULL; struct nv_pmu_boardobj *ppmudata = NULL; u8 index; gk20a_dbg_info(""); if (pboardobjgrp == NULL) return -EINVAL; if (pboardobjgrppmu == NULL) return -EINVAL; /* Initialize the PMU HDR data.*/ status = pboardobjgrp->pmuhdrdatainit(g, pboardobjgrp, pboardobjgrppmu, pboardobjgrp->mask); if (status) { nvgpu_err(g, "unable to init boardobjgrp pmuhdr data"); goto boardobjgrppmudatainit_super_done; } BOARDOBJGRP_FOR_EACH(pboardobjgrp, struct boardobj*, pboardobj, index) { status = pboardobjgrp->pmudatainstget(g, (struct nv_pmu_boardobjgrp *)pboardobjgrppmu, &ppmudata, index); if (status) { nvgpu_err(g, "could not get object instance"); goto boardobjgrppmudatainit_super_done; } /* Initialize the PMU Data and send to PMU */ status = pboardobj->pmudatainit(g, pboardobj, ppmudata); if (status) { nvgpu_err(g, "could not parse pmu for device %d", index); goto boardobjgrppmudatainit_super_done; } } boardobjgrppmudatainit_super_done: gk20a_dbg_info(" Done"); return status; } u32 boardobjgrp_pmuset_impl(struct gk20a *g, struct boardobjgrp *pboardobjgrp) { u32 status = 0; struct boardobjgrp_pmu_cmd *pcmd = &pboardobjgrp->pmu.set; gk20a_dbg_info(""); if (pboardobjgrp == NULL) return -EINVAL; if (!pboardobjgrp->bconstructed) return -EINVAL; if (pboardobjgrp->pmu.unitid == BOARDOBJGRP_UNIT_ID_INVALID) return -EINVAL; if (pboardobjgrp->pmu.classid == BOARDOBJGRP_GRP_CLASS_ID_INVALID) return -EINVAL; if (pboardobjgrp->pmu.set.id == BOARDOBJGRP_GRP_CMD_ID_INVALID) return -EINVAL; if ((pcmd->hdrsize == 0) || (pcmd->entrysize == 0) || (pcmd->buf == NULL)) return -EINVAL; /* If no objects in the group, return early */ if (BOARDOBJGRP_IS_EMPTY(pboardobjgrp)) return -EINVAL; /* Initialize PMU buffer with BOARDOBJGRP data. */ memset(pcmd->buf, 0x0, pcmd->fbsize); status = pboardobjgrp->pmudatainit(g, pboardobjgrp, pcmd->buf); if (status) { nvgpu_err(g, "could not parse pmu data"); goto boardobjgrp_pmuset_exit; } /* * Reset the boolean that indicates set status for most recent * instance of BOARDOBJGRP. */ pboardobjgrp->pmu.bset = false; /* * alloc mem in vidmem & copy constructed pmu boardobjgrp data from * sysmem to vidmem */ if (pcmd->surf.vidmem_desc.size == 0) { nvgpu_pmu_vidmem_surface_alloc(g, &pcmd->surf.vidmem_desc, pcmd->fbsize); } nvgpu_mem_wr_n(g, &pcmd->surf.vidmem_desc, 0, pcmd->buf, pcmd->fbsize); /* Send the SET PMU CMD to the PMU */ status = boardobjgrp_pmucmdsend(g, pboardobjgrp, pcmd); if (status) { nvgpu_err(g, "could not send SET CMD to PMU"); goto boardobjgrp_pmuset_exit; } pboardobjgrp->pmu.bset = true; boardobjgrp_pmuset_exit: return status; } u32 boardobjgrp_pmugetstatus_impl(struct gk20a *g, struct boardobjgrp *pboardobjgrp, struct boardobjgrpmask *mask) { u32 status = 0; struct boardobjgrp_pmu_cmd *pcmd = &pboardobjgrp->pmu.getstatus; struct boardobjgrp_pmu_cmd *pset = &pboardobjgrp->pmu.set; gk20a_dbg_info(""); if (pboardobjgrp == NULL) return -EINVAL; if (!pboardobjgrp->bconstructed) return -EINVAL; if (pboardobjgrp->pmu.unitid == BOARDOBJGRP_UNIT_ID_INVALID) return -EINVAL; if (pboardobjgrp->pmu.classid == BOARDOBJGRP_GRP_CLASS_ID_INVALID) return -EINVAL; if (pboardobjgrp->pmu.set.id == BOARDOBJGRP_GRP_CMD_ID_INVALID) return -EINVAL; if ((pcmd->hdrsize == 0) || (pcmd->entrysize == 0) || (pcmd->buf == NULL)) return -EINVAL; /* If no objects in the group, return early */ if (BOARDOBJGRP_IS_EMPTY(pboardobjgrp)) return -EINVAL; /* * Can only GET_STATUS if the BOARDOBJGRP has been previously SET to the * PMU */ if (!pboardobjgrp->pmu.bset) return -EINVAL; /* * alloc mem in vidmem & copy constructed pmu boardobjgrp data from * sysmem to vidmem */ if (pcmd->surf.vidmem_desc.size == 0) { nvgpu_pmu_vidmem_surface_alloc(g, &pcmd->surf.vidmem_desc, pcmd->fbsize); } /* * Initialize PMU buffer with the mask of BOARDOBJGRPs for which to * retrieve status */ memset(pcmd->buf, 0x0, pcmd->fbsize); status = pboardobjgrp->pmuhdrdatainit(g, pboardobjgrp, pcmd->buf, mask); if (status) { nvgpu_err(g, "could not init PMU HDR data"); goto boardobjgrp_pmugetstatus_exit; } nvgpu_mem_wr_n(g, &pcmd->surf.vidmem_desc, 0, pset->buf, pset->hdrsize); /* Send the GET_STATUS PMU CMD to the PMU */ status = boardobjgrp_pmucmdsend(g, pboardobjgrp, &pboardobjgrp->pmu.getstatus); if (status) { nvgpu_err(g, "could not send GET_STATUS cmd to PMU"); goto boardobjgrp_pmugetstatus_exit; } /*copy the data back to sysmem buffer that belongs to command*/ nvgpu_mem_rd_n(g, &pcmd->surf.vidmem_desc, 0, pcmd->buf, pcmd->fbsize); boardobjgrp_pmugetstatus_exit: return status; } static u32 boardobjgrp_objinsert_final(struct boardobjgrp *pboardobjgrp, struct boardobj *pboardobj, u8 index) { gk20a_dbg_info(""); if (pboardobjgrp == NULL) return -EINVAL; if (pboardobj == NULL) return -EINVAL; if (index > pboardobjgrp->objslots) return -EINVAL; if (pboardobjgrp->ppobjects[index] != NULL) return -EINVAL; /* * Check that this BOARDOBJ has not already been added to a * BOARDOBJGRP */ if (pboardobj->idx != CTRL_BOARDOBJ_IDX_INVALID) return -EINVAL; pboardobjgrp->ppobjects[index] = pboardobj; pboardobjgrp->objmaxidx = BOARDOBJGRP_IS_EMPTY(pboardobjgrp) ? index : max(pboardobjgrp->objmaxidx, index); pboardobj->idx = index; pboardobjgrp->objmask |= BIT(index); gk20a_dbg_info(" Done"); return boardobjgrpmask_bitset(pboardobjgrp->mask, index); } static struct boardobj *boardobjgrp_objgetbyidx_final( struct boardobjgrp *pboardobjgrp, u8 index) { if (!boardobjgrp_idxisvalid(pboardobjgrp, index)) return NULL; return pboardobjgrp->ppobjects[index]; } static struct boardobj *boardobjgrp_objgetnext_final( struct boardobjgrp *pboardobjgrp, u8 *currentindex, struct boardobjgrpmask *mask) { struct boardobj *pboardobjnext = NULL; u8 objmaxidx; u8 index; if (currentindex == NULL) return NULL; if (pboardobjgrp == NULL) return NULL; /* Search from next element unless first object was requested */ index = (*currentindex != CTRL_BOARDOBJ_IDX_INVALID) ? (*currentindex + 1) : 0; /* For the cases below in which we have to return NULL */ *currentindex = CTRL_BOARDOBJ_IDX_INVALID; /* Validate provided mask */ if (mask != NULL) { if (!(boardobjgrpmask_sizeeq(pboardobjgrp->mask, mask))) return NULL; } objmaxidx = pboardobjgrp->objmaxidx; if (objmaxidx != CTRL_BOARDOBJ_IDX_INVALID) { for (; index <= objmaxidx; index++) { pboardobjnext = pboardobjgrp->ppobjects[index]; if (pboardobjnext != NULL) { /* Filter results using client provided mask.*/ if (mask != NULL) { if (!boardobjgrpmask_bitget(mask, index)) { pboardobjnext = NULL; continue; } } *currentindex = index; break; } } } return pboardobjnext; } static u32 boardobjgrp_objremoveanddestroy_final( struct boardobjgrp *pboardobjgrp, u8 index) { u32 status = 0; u32 stat; gk20a_dbg_info(""); if (!boardobjgrp_idxisvalid(pboardobjgrp, index)) return -EINVAL; if (pboardobjgrp->objmaxidx == CTRL_BOARDOBJ_IDX_INVALID) return -EINVAL; status = pboardobjgrp->ppobjects[index]->destruct( pboardobjgrp->ppobjects[index]); pboardobjgrp->ppobjects[index] = NULL; pboardobjgrp->objmask &= ~BIT(index); stat = boardobjgrpmask_bitclr(pboardobjgrp->mask, index); if (stat) { if (status == 0) status = stat; } /* objmaxidx requires update only if that very object was removed */ if (pboardobjgrp->objmaxidx == index) { pboardobjgrp->objmaxidx = boardobjgrpmask_bitidxhighest(pboardobjgrp->mask); } return status; } void boardobjgrpe32hdrset(struct nv_pmu_boardobjgrp *hdr, u32 objmask) { u32 slots = objmask; gk20a_dbg_info(""); HIGHESTBITIDX_32(slots); slots++; hdr->super.type = CTRL_BOARDOBJGRP_TYPE_E32; hdr->super.class_id = 0; hdr->super.obj_slots = (u8)slots; hdr->obj_mask = objmask; } static void boardobjgrp_pmucmdhandler(struct gk20a *g, struct pmu_msg *msg, void *param, u32 handle, u32 status) { struct nv_pmu_boardobj_msg_grp *pgrpmsg; struct boardobjgrp_pmucmdhandler_params *phandlerparams = (struct boardobjgrp_pmucmdhandler_params *)param; struct boardobjgrp *pboardobjgrp = phandlerparams->pboardobjgrp; struct boardobjgrp_pmu_cmd *pgrpcmd = phandlerparams->pcmd; gk20a_dbg_info(""); pgrpmsg = &msg->msg.boardobj.grp; if (pgrpmsg->class_id != pboardobjgrp->pmu.classid) { nvgpu_err(g, "Unrecognized GRP type: unit %x class id=0x%02x cmd id %x", msg->hdr.unit_id, pboardobjgrp->pmu.classid, pgrpcmd->id); return; } if (msg->msg.boardobj.msg_type != pgrpcmd->msgid) { nvgpu_err(g, "unsupported msg for unit %x class %x cmd id %x msg %x", msg->hdr.unit_id, pboardobjgrp->pmu.classid, pgrpcmd->id, msg->msg.boardobj.msg_type); return; } if (msg->msg.boardobj.grp_set.flcn_status != 0) { nvgpu_err(g, "cmd abort for unit %x class %x cmd id %x status %x", msg->hdr.unit_id, pboardobjgrp->pmu.classid, pgrpcmd->id, msg->msg.boardobj.grp_set.flcn_status); return; } phandlerparams->success = pgrpmsg->b_success ? 1 : 0; if (!pgrpmsg->b_success) { nvgpu_err(g, "failed GRPCMD: msgtype=0x%x, classid=0x%x, cmd id %x", pgrpmsg->msg_type, pgrpmsg->class_id, pgrpcmd->id); return; } } static u32 boardobjgrp_pmucmdsend(struct gk20a *g, struct boardobjgrp *pboardobjgrp, struct boardobjgrp_pmu_cmd *pcmd) { struct boardobjgrp_pmucmdhandler_params handlerparams; struct pmu_payload payload; struct nv_pmu_boardobj_cmd_grp *pgrpcmd; struct pmu_cmd cmd; u32 seqdesc; u32 status = 0; gk20a_dbg_info(""); memset(&payload, 0, sizeof(payload)); memset(&handlerparams, 0, sizeof(handlerparams)); memset(&cmd, 0, sizeof(struct pmu_cmd)); cmd.hdr.unit_id = pboardobjgrp->pmu.unitid; cmd.hdr.size = sizeof(struct nv_pmu_boardobj_cmd_grp) + sizeof(struct pmu_hdr); pgrpcmd = &cmd.cmd.boardobj.grp; pgrpcmd->cmd_type = pcmd->id; pgrpcmd->class_id = pboardobjgrp->pmu.classid; pgrpcmd->grp.hdr_size = pcmd->hdrsize; pgrpcmd->grp.entry_size = pcmd->entrysize; /* * copy vidmem information to boardobj_cmd_grp */ nvgpu_pmu_surface_describe(g, &pcmd->surf.vidmem_desc, &pgrpcmd->grp.fb); /* * PMU reads command from sysmem so assigned * "payload.in.buf = pcmd->buf" * but PMU access pmu boardobjgrp data from vidmem copied above */ payload.in.buf = pcmd->buf; payload.in.size = max(pcmd->hdrsize, pcmd->entrysize); payload.in.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED; payload.in.offset = offsetof(struct nv_pmu_boardobj_cmd_grp, grp); /* Setup the handler params to communicate back results.*/ handlerparams.pboardobjgrp = pboardobjgrp; handlerparams.pcmd = pcmd; handlerparams.success = 0; status = nvgpu_pmu_cmd_post(g, &cmd, NULL, &payload, PMU_COMMAND_QUEUE_LPQ, boardobjgrp_pmucmdhandler, (void *)&handlerparams, &seqdesc, ~0); if (status) { nvgpu_err(g, "unable to post boardobj grp cmd for unit %x cmd id %x", cmd.hdr.unit_id, pcmd->id); goto boardobjgrp_pmucmdsend_exit; } pmu_wait_message_cond(&g->pmu, gk20a_get_gr_idle_timeout(g), &handlerparams.success, 1); if (handlerparams.success == 0) { nvgpu_err(g, "could not process cmd"); status = -ETIMEDOUT; goto boardobjgrp_pmucmdsend_exit; } boardobjgrp_pmucmdsend_exit: return status; }