in common/recipes-core/ncsi-util/files/ncsi-util.c [305:535]
static int pldm_update_fw(char *path, int pldm_bufsize, uint8_t ch)
{
#define SLEEP_TIME_MS 20 // wait time per loop in ms
NCSI_NL_MSG_T *nl_msg = NULL;
NCSI_NL_RSP_T *nl_resp = NULL;
pldm_fw_pkg_hdr_t *pkgHdr;
pldm_cmd_req pldmReq = {0};
pldm_response *pldmRes = NULL;
int pldmCmdStatus = 0;
int i = 0, j = 0;
int ret = 0;
int waitcycle = 0;
int waitTOsec = 0;
int currnet_state = -1, previous_state = -1;
char value[64];
struct timespec ts;
#define MAX_WAIT_CYCLE 1000
clock_gettime(CLOCK_MONOTONIC, &ts);
snprintf(value, sizeof(value), "%ld", ts.tv_sec + 600);
kv_set("block_ncsi_xmit", value, 0, 0);
nl_msg = calloc(1, sizeof(NCSI_NL_MSG_T));
if (!nl_msg) {
printf("%s, Error: failed nl_msg buffer allocation(%d)\n",
__FUNCTION__, sizeof(NCSI_NL_MSG_T));
ret = -1;
goto free_exit;
}
memset(nl_msg, 0, sizeof(NCSI_NL_MSG_T));
pldmRes = calloc(1, sizeof(pldm_response));
if (!pldmRes) {
printf("%s, Error: failed pldmRes buffer allocation(%d)\n",
__FUNCTION__, sizeof(pldm_response));
ret = -1;
goto free_exit;
}
pkgHdr = pldm_parse_fw_pkg(path);
if (!pkgHdr) {
ret = -1;
goto free_exit;
}
pldmCreateReqUpdateCmd(pkgHdr, &pldmReq, pldm_bufsize);
printf("\n01 PldmRequestUpdateOp: payload_size=%d\n", pldmReq.payload_size);
ret = create_ncsi_ctrl_pkt(nl_msg, ch, NCSI_PLDM_REQUEST, pldmReq.payload_size,
&(pldmReq.common[0]));
if (ret) {
goto free_exit;
}
if (sendPldmCmdAndCheckResp(nl_msg) != CC_SUCCESS) {
ret = -1;
goto free_exit;
}
for (i=0; i<pkgHdr->componentImageCnt; ++i) {
memset(&pldmReq, 0, sizeof(pldm_cmd_req));
pldmCreatePassComponentTblCmd(pkgHdr, i, &pldmReq);
printf("\n02 PldmPassComponentTableOp[%d]: payload_size=%d\n", i,
pldmReq.payload_size);
ret = create_ncsi_ctrl_pkt(nl_msg, ch, NCSI_PLDM_REQUEST, pldmReq.payload_size,
&(pldmReq.common[0]));
if (ret) {
goto free_exit;
}
if (sendPldmCmdAndCheckResp(nl_msg) != CC_SUCCESS) {
ret = -1;
goto free_exit;
}
}
for (i=0; i<pkgHdr->componentImageCnt; ++i) {
memset(&pldmReq, 0, sizeof(pldm_cmd_req));
pldmCreateUpdateComponentCmd(pkgHdr, i, &pldmReq);
printf("\n03 PldmUpdateComponentOp[%d]: payload_size=%d\n", i,
pldmReq.payload_size);
ret = create_ncsi_ctrl_pkt(nl_msg, ch, NCSI_PLDM_REQUEST, pldmReq.payload_size,
&(pldmReq.common[0]));
if (ret) {
goto free_exit;
}
if (sendPldmCmdAndCheckResp(nl_msg) != CC_SUCCESS) {
ret = -1;
goto free_exit;
}
}
// FW data transfer
int loopCount = 0;
int idleCnt = 0;
int pldmCmd = 0;
setPldmTimeout(CMD_UPDATE_COMPONENT, &waitTOsec);
while (idleCnt < (waitTOsec * 1000 /SLEEP_TIME_MS) ) {
// printf("\n04 QueryPendingNcPldmRequestOp, loop=%d\n", loopCount);
ret = create_ncsi_ctrl_pkt(nl_msg, ch, NCSI_QUERY_PENDING_NC_PLDM_REQ, 0, NULL);
if (ret) {
goto free_exit;
}
nl_resp = send_nl_msg_retry(nl_msg);
if (!nl_resp) {
ret = -1;
goto free_exit;
}
print_pldm_cmd_status(nl_resp);
pldmCmd = ncsiGetPldmCmd(nl_resp, &pldmReq);
free(nl_resp);
nl_resp = NULL;
if (pldmCmd == -1) {
// printf("No pending command, loop %d\n", idleCnt);
msleep(SLEEP_TIME_MS); // wait some time and try again
idleCnt++;
continue;
} else {
idleCnt = 0;
}
if ( (pldmCmd == CMD_REQUEST_FIRMWARE_DATA) ||
(pldmCmd == CMD_TRANSFER_COMPLETE) ||
(pldmCmd == CMD_VERIFY_COMPLETE) ||
(pldmCmd == CMD_APPLY_COMPLETE)) {
setPldmTimeout(pldmCmd, &waitTOsec);
loopCount++;
waitcycle = 0;
pldmCmdStatus = pldmFwUpdateCmdHandler(pkgHdr, &pldmReq, pldmRes);
ret = create_ncsi_ctrl_pkt(nl_msg, ch, NCSI_SEND_NC_PLDM_REPLY,
pldmRes->resp_size, pldmRes->common);
if (ret) {
goto free_exit;
}
nl_resp = send_nl_msg_retry(nl_msg);
if (!nl_resp) {
ret = -1;
goto free_exit;
}
//print_ncsi_resp(nl_resp);
free(nl_resp);
nl_resp = NULL;
if ((pldmCmd == CMD_APPLY_COMPLETE) || (pldmCmdStatus == -1))
break;
if (nl_conf == 0) // Linux 4.1
msleep(10); // add dealy to reduce retry sending request to NIC
} else {
printf("unknown PLDM cmd 0x%x\n", pldmCmd);
waitcycle++;
if (waitcycle >= MAX_WAIT_CYCLE) {
printf("max wait cycle exceeded, exit\n");
break;
}
}
}
// only activate FW if update loop exists with good status
if (!pldmCmdStatus && (pldmCmd == CMD_APPLY_COMPLETE)) {
// update successful, activate FW
memset(&pldmReq, 0, sizeof(pldm_cmd_req));
pldmCreateActivateFirmwareCmd(&pldmReq);
printf("\n05 PldmActivateFirmwareOp\n");
ret = create_ncsi_ctrl_pkt(nl_msg, ch, NCSI_PLDM_REQUEST, pldmReq.payload_size,
&(pldmReq.common[0]));
if (ret) {
goto free_exit;
}
if (sendPldmCmdAndCheckResp(nl_msg) != CC_SUCCESS) {
for (j=0; j<5; j++) {
sleep(2);
memset(&pldmReq, 0, sizeof(pldm_cmd_req));
pldmCreateGetStatusCmd(&pldmReq);
ret = create_ncsi_ctrl_pkt(nl_msg, ch, NCSI_PLDM_REQUEST, pldmReq.payload_size,
&(pldmReq.common[0]));
if (ret) {
printf("\nPldmGetStatus fail ret=%d\n",ret);
goto free_exit;
}
nl_resp = send_nl_msg(nl_msg);
if (!nl_resp) {
printf("\nPldmGetStatus send_nl_msg fail\n");
ret = -1;
goto free_exit;
}
print_pldm_cmd_status(nl_resp);
print_pldm_resp_raw(nl_resp);
currnet_state = nl_resp->msg_payload[8];
previous_state = nl_resp->msg_payload[9];
free(nl_resp);
nl_resp = NULL;
if (currnet_state == STATE_IDLE && previous_state == STATE_ACTIVATE) {
ret = 0;
break;
} else {
ret = -1;
}
}
}
} else {
printf("PLDM cmd (%d) failed (status %d), abort update\n",
pldmCmd, pldmCmdStatus);
// send abort update cmd
memset(&pldmReq, 0, sizeof(pldm_cmd_req));
pldmCreateCancelUpdateCmd(&pldmReq);
ret = create_ncsi_ctrl_pkt(nl_msg, ch, NCSI_PLDM_REQUEST, pldmReq.payload_size,
&(pldmReq.common[0]));
if (ret) {
ret = -1;
goto free_exit;
}
// ignore the return status and exit since this is on the error path
sendPldmCmdAndCheckResp(nl_msg);
ret = -1;
}
free_exit:
if (pkgHdr)
free_pldm_pkg_data(&pkgHdr);
if (nl_resp)
free(nl_resp);
if (pldmRes)
free(pldmRes);
if (nl_msg)
free(nl_msg);
return ret;
}