in fboss/lib/i2c/FirmwareUpgrader.cpp [92:327]
bool CmisFirmwareUpgrader::cmisModuleFirmwareDownload(
const uint8_t* imageBuf,
int imageLen) {
uint8_t startCommandPayloadSize = 0;
bool status;
int imageOffset, imageChunkLen;
bool eplSupported = false;
XLOG(INFO) << folly::sformat(
"cmisModuleFirmwareDownload: Mod{:d}: Starting to download the image with length {:d}",
moduleId_,
imageLen);
// Set the password to let the privileged operation of firmware download
bus_->moduleWrite(
moduleId_,
{TransceiverI2CApi::ADDR_QSFP, kModulePasswordEntryReg, 4},
msaPassword_.data());
CdbCommandBlock commandBlockBuf;
CdbCommandBlock* commandBlock = &commandBlockBuf;
// Basic validation first. Check if the firmware download is allowed by
// issuing the Query command to CDB
commandBlock->createCdbCmdModuleQuery();
// Run the CDB command
status = commandBlock->cmisRunCdbCommand(bus_, moduleId_);
if (status) {
// Query result will be in LPL memory at byte offset 2
if (commandBlock->getCdbRlplLength() >= 3) {
if (commandBlock->getCdbLplFlatMemory()[2] == 0) {
// This should not happen because before calling this function
// we supply the password to module to allow priviledged
// operation. But still download feature is not available here
// so return false here
XLOG(INFO) << folly::sformat(
"cmisModuleFirmwareDownload: Mod{:d}: The firmware download feature is locked by vendor",
moduleId_);
return false;
}
}
} else {
// The QUERY command can fail if the module is in bootloader mode
// Not able to determine CDB module status but don't return from here
XLOG(INFO) << folly::sformat(
"cmisModuleFirmwareDownload: Mod{:d}: Could not get result from CDB Query command",
moduleId_);
}
// Step 0: Retrieve the Start Command Payload Size (the image header size)
// Done by sending Firmware upgrade feature command to CDB
commandBlock->createCdbCmdGetFwFeatureInfo();
// Run the CDB command
status = commandBlock->cmisRunCdbCommand(bus_, moduleId_);
// If the CDB command is successfull then the Start Command Payload Size is
// returned by CDB in LPL memory at offset 2
if (status && commandBlock->getCdbRlplLength() >= 3) {
// Get the firmware header size from CDB
startCommandPayloadSize = commandBlock->getCdbLplFlatMemory()[2];
// Check if EPL memory is supported
if (commandBlock->getCdbLplFlatMemory()[5] == 0x10 ||
commandBlock->getCdbLplFlatMemory()[5] == 0x11) {
eplSupported = true;
XLOG(INFO) << folly::sformat(
"cmisModuleFirmwareDownload: Mod{:d} will use EPL memory for firmware download",
moduleId_);
}
} else {
XLOG(INFO) << folly::sformat(
"cmisModuleFirmwareDownload: Mod{:d}: Could not get result from CDB Firmware Update Feature command",
moduleId_);
// Sometime when the optics is in boot loader mode, this CDB command
// fails. So fill in the header size if it is a known optics otherwise
// return false
startCommandPayloadSize = imageHeaderLen_;
XLOG(INFO) << folly::sformat(
"cmisModuleFirmwareDownload: Mod{:d}: Setting the module startCommandPayloadSize as {:d}",
moduleId_,
startCommandPayloadSize);
}
XLOG(INFO) << folly::sformat(
"cmisModuleFirmwareDownload: Mod{:d}: Step 0: Got Start Command Payload Size as {:d}",
moduleId_,
startCommandPayloadSize);
// Validate if the image length is greater than this. If not then our new
// image is bad
if (imageLen < startCommandPayloadSize) {
XLOG(INFO) << folly::sformat(
"cmisModuleFirmwareDownload: Mod{:d}: The image length {:d} is smaller than startCommandPayloadSize {:d}",
moduleId_,
imageLen,
startCommandPayloadSize);
return false;
}
// Step 1: Issue CDB command: Firmware Download start
imageChunkLen = startCommandPayloadSize;
commandBlock->createCdbCmdFwDownloadStart(
startCommandPayloadSize, imageLen, imageOffset, imageBuf);
// Run the CDB command
status = commandBlock->cmisRunCdbCommand(bus_, moduleId_);
if (!status) {
// DOWNLOAD_START command failed
XLOG(INFO) << folly::sformat(
"cmisModuleFirmwareDownload: Mod{:d}: Could not run the CDB Firmware Download Start command",
moduleId_);
return false;
}
XLOG(INFO) << folly::sformat(
"cmisModuleFirmwareDownload: Mod{:d}: Step 1: Issued Firmware download start command successfully",
moduleId_);
// Step 2: Issue CDB command: Firmware Download image
XLOG(INFO) << folly::sformat(
"cmisModuleFirmwareDownload: Mod{:d}: Step 2: Issuing Firmware Download Image command. Starting offset: {:d}",
moduleId_,
imageOffset);
while (imageOffset < imageLen) {
if (!eplSupported) {
// Create CDB command block using internal LPL memory
commandBlock->createCdbCmdFwDownloadImageLpl(
startCommandPayloadSize,
imageLen,
imageBuf,
imageOffset,
imageChunkLen);
} else {
// Create CDB command block assuming external EPL memory
commandBlock->createCdbCmdFwDownloadImageEpl(
startCommandPayloadSize, imageLen, imageOffset, imageChunkLen);
// Write the image payload to external EPL before invoking the command
commandBlock->writeEplPayload(
bus_, moduleId_, imageBuf, imageOffset, imageChunkLen);
}
// Run the CDB command
status = commandBlock->cmisRunCdbCommand(bus_, moduleId_);
if (!status) {
// DOWNLOAD_IMAGE command failed
XLOG(INFO) << folly::sformat(
"cmisModuleFirmwareDownload: Mod{:d}: Could not run the CDB Firmware Download Image command",
moduleId_);
return false;
}
XLOG(INFO) << folly::sformat(
"cmisModuleFirmwareDownload: Mod{:d}: Image wrote, offset: {:d} .. {:d}",
moduleId_,
imageOffset - imageChunkLen,
imageOffset);
}
XLOG(INFO) << folly::sformat(
"cmisModuleFirmwareDownload: Mod{:d}: Step 2: Issued Firmware Download Image successfully. Downloaded file size {:d}",
moduleId_,
imageOffset);
// Step 3: Issue CDB command: Firmware download complete
commandBlock->createCdbCmdFwDownloadComplete();
// Run the CDB command
status = commandBlock->cmisRunCdbCommand(bus_, moduleId_);
if (!status) {
// DOWNLOAD_COMPLETE command failed
XLOG(INFO) << folly::sformat(
"cmisModuleFirmwareDownload: Mod{:d}: Could not run the CDB Firmware Download Complete command",
moduleId_);
// Send the DOWNLOAD_ABORT command to CDB and return.
return false;
}
XLOG(INFO) << folly::sformat(
"cmisModuleFirmwareDownload: Mod{:d}: Step 3: Issued Firmware download complete command successfully",
moduleId_);
// Non App images like DSP image don't need last 2 steps (Run, Commit) for the
// firmware download
if (!appImage_) {
return true;
}
// Step 4: Issue CDB command: Run the downloaded firmware
commandBlock->createCdbCmdFwImageRun();
// Run the CDB command
// No need to check status because RUN command issues soft reset to CDB
// so we can't check status here
status = commandBlock->cmisRunCdbCommand(bus_, moduleId_);
XLOG(INFO) << folly::sformat(
"cmisModuleFirmwareDownload: Mod{:d}: Step 4: Issued Firmware download Run command successfully",
moduleId_);
usleep(2 * moduleDatapathInitDurationUsec);
// Set the password to let the privileged operation of firmware download
bus_->moduleWrite(
moduleId_,
{TransceiverI2CApi::ADDR_QSFP, kModulePasswordEntryReg, 4},
msaPassword_.data());
// Step 5: Issue CDB command: Commit the downloaded firmware
commandBlock->createCdbCmdFwCommit();
// Run the CDB command
status = commandBlock->cmisRunCdbCommand(bus_, moduleId_);
if (!status) {
XLOG(INFO) << folly::sformat(
"cmisModuleFirmwareDownload: Mod{:d}: Step 5: Issued Firmware commit command failed",
moduleId_);
} else {
XLOG(INFO) << folly::sformat(
"cmisModuleFirmwareDownload: Mod{:d}: Step 5: Issued Firmware commit command successful",
moduleId_);
}
usleep(10 * moduleDatapathInitDurationUsec);
// Set the password to let the privileged operation of firmware download
bus_->moduleWrite(
moduleId_,
{TransceiverI2CApi::ADDR_QSFP, kModulePasswordEntryReg, 4},
msaPassword_.data());
return true;
}