meta-facebook/meta-fby3/recipes-fby3/fw-util/files/bmc_cpld_capsule.cpp (436 lines of code) (raw):
#include <string>
#include <cstdio>
#include <cstring>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <syslog.h>
#include <openbmc/obmc-i2c.h>
#include "bmc_cpld_capsule.h"
#include <facebook/bic.h>
#include <openbmc/pal.h>
using namespace std;
image_info BmcCpldCapsuleComponent::check_image(string image, bool force) {
uint8_t bmc_location = 0;
string fru_name = fru();
string bmc_str = "bmc";
size_t bmc_found = fru_name.find(bmc_str);
struct stat f_stat;
string comp = component();
image_info image_sts = {"", false};
if (comp != "cpld_cap" && comp != "cpld_cap_rcvy") {
image_sts.new_path = image;
image_sts.result = true;
return image_sts;
}
if ( fby3_common_get_bmc_location(&bmc_location) < 0 ) {
printf("Failed to initialize the fw-util\n");
exit(EXIT_FAILURE);
}
//create a new tmp image
image_sts.new_path = image + "-tmp";
//open the binary
int fd_r = open(image.c_str(), O_RDONLY);
if (fd_r < 0) {
cerr << "Cannot open " << image << " for reading" << endl;
return image_sts;
}
// create a tmp image for writing.
int fd_w = open(image_sts.new_path.c_str(), O_WRONLY | O_CREAT, 0666);
if (fd_w < 0) {
cerr << "Cannot write to " << image_sts.new_path << endl;
close(fd_r);
return image_sts;
}
if (stat(image.c_str(), &f_stat) == -1) {
return image_sts;
}
long size = (long)f_stat.st_size;
uint8_t *memblock = new uint8_t [size];//data_size + signed byte
uint8_t signed_byte = 0;
size_t r_b = read(fd_r, memblock, size);
size_t w_b = 0;
signed_byte = memblock[size - 1] & 0xf;
r_b = r_b - 1; //only write data to tmp image
w_b = write(fd_w, memblock, r_b);
//check size
if ( r_b != w_b ) {
cerr << "Cannot create the tmp image - " << image_sts.new_path << endl;
cerr << "Read: " << r_b << " Write: " << w_b << endl;
image_sts.result = false;
}
if ( force == false ) {
//CPLD is located on class 2(NIC_EXP)
if ( bmc_location == NIC_BMC ) {
if ( (signed_byte == NICEXP) && (bmc_found != string::npos) ) {
image_sts.result = true;
} else {
cout << "image is not a valid CPLD image for " << fru_name << endl;
}
} else if ( (bmc_location == BB_BMC) || (bmc_location == DVT_BB_BMC) ) {
if ( (signed_byte == BICBB) && (bmc_found != string::npos) ) {
image_sts.result = true;
} else {
cout << "image is not a valid CPLD image for " << fru_name << endl;
}
}
}
//release the resource
close(fd_r);
close(fd_w);
delete[] memblock;
return image_sts;
}
int BmcCpldCapsuleComponent::set_pfr_cap_ver_str(string image, string comp) {
int ret = 0;
uint32_t ver_reg = 0x60;
uint8_t tbuf[18] = {0x00};
uint8_t tlen = 0;
int roffset = 0;
int frlen = 0;
int i2cfd = 0;
if (comp == "cpld_cap") {
ver_reg = 0x64;
tlen = CPLD_CAP_VER_LEN;
roffset = CPLD_CAP_VER_OFFSET;
frlen = CPLD_CAP_VER_OFFSET + CPLD_CAP_VER_LEN;
} else if (comp == "cpld_cap_rcvy") {
ver_reg = 0x64;
tlen = CPLD_CAP_VER_LEN;
roffset = CPLD_CAP_VER_OFFSET;
frlen = CPLD_CAP_VER_OFFSET + CPLD_CAP_VER_LEN;
}
//open the binary
int fd_r = open(image.c_str(), O_RDONLY);
if (fd_r < 0) {
cerr << "Cannot open " << image << " for reading" << endl;
return -1;
}
uint8_t *memblock = new uint8_t [frlen];//data_size + signed byte
size_t r_b = read(fd_r, memblock, frlen);
close(fd_r);
if (r_b <= 0) return -1;
memcpy(tbuf, (uint8_t *)&ver_reg, 1);
memcpy(&tbuf[1], &memblock[roffset], tlen);
tlen = tlen + 1;
string i2cdev = "/dev/i2c-" + to_string(bus);
if ((i2cfd = open(i2cdev.c_str(), O_RDWR)) < 0) {
printf("Failed to open %s\n", i2cdev.c_str());
return -1;
}
if (ioctl(i2cfd, I2C_SLAVE, CPLD_INTENT_CTRL_ADDR) < 0) {
printf("Failed to talk to slave@0x%02X\n", CPLD_INTENT_CTRL_ADDR);
} else {
ret = i2c_rdwr_msg_transfer(i2cfd, CPLD_INTENT_CTRL_ADDR, tbuf, tlen, NULL, 0);
}
if ( i2cfd > 0 ) close(i2cfd);
return ret;
}
int BmcCpldCapsuleComponent::get_pfr_recovery_ver_str(string& s, string comp) {
int ret = 0;
char ver[32] = {0};
uint32_t ver_reg = 0x60;
uint8_t tbuf[1] = {0x00};
uint8_t rbuf[4] = {0x00};
uint8_t tlen = 1;
uint8_t rlen = 4;
int i2cfd = 0;
if (comp == "cpld_cap") {
ver_reg = 0x64;
} else if (comp == "cpld_cap_rcvy") {
ver_reg = 0x60;
}
memcpy(tbuf, (uint8_t *)&ver_reg, tlen);
string i2cdev = "/dev/i2c-" + to_string(bus);
if ((i2cfd = open(i2cdev.c_str(), O_RDWR)) < 0) {
printf("Failed to open %s\n", i2cdev.c_str());
return -1;
}
if (ioctl(i2cfd, I2C_SLAVE, CPLD_INTENT_CTRL_ADDR) < 0) {
printf("Failed to talk to slave@0x%02X\n", CPLD_INTENT_CTRL_ADDR);
} else {
ret = i2c_rdwr_msg_transfer(i2cfd, CPLD_INTENT_CTRL_ADDR, tbuf, tlen, rbuf, rlen);
snprintf(ver, sizeof(ver), "%02X%02X%02X%02X", rbuf[3], rbuf[2], rbuf[1], rbuf[0]);
}
if ( i2cfd > 0 ) close(i2cfd);
s = string(ver);
return ret;
}
int BmcCpldCapsuleComponent::get_bmc_stg_cap_version(string& s) {
// parsering the image to get the version string
int mtd_no;
char rbuf[256], mtd_name[32], dev[16] = {0}, cmd[128];
FILE *fp;
if ((fp = fopen("/proc/mtd", "r"))) {
while (fgets(rbuf, sizeof(rbuf), fp)) {
if ((sscanf(rbuf, "mtd%d: %*x %*x %s", &mtd_no, mtd_name) == 2) &&
!strcmp("\"stg-bmc\"", mtd_name)) {
sprintf(dev, "/dev/mtd%d", mtd_no);
break;
}
}
fclose(fp);
}
if (!dev[0] || !(fp = fopen(dev, "rb"))) {
printf("stg-bmc not found\n");
return -1;
}
fclose(fp);
snprintf(cmd, sizeof(cmd),
"dd if=%s bs=64k count=6 2>/dev/null | strings | grep -E 'U-Boot 20[[:digit:]]{2}\\.[[:digit:]]{2}'",
dev);
fp = popen(cmd, "r");
if (fp) {
char line[256];
char *ver = 0;
while (fgets(line, sizeof(line), fp)) {
int ret;
ret = sscanf(line, "U-Boot 20%*2d.%*2d%*[ ]%m[^ \n]%*[ ](%*[^)])\n", &ver);
if (1 == ret) {
s = string(ver);
break;
}
}
if (ver) {
free(ver);
}
pclose(fp);
}
return 0;
}
int BmcCpldCapsuleComponent::bmc_update_capsule(string image) {
FILE *fp;
int i2cfd = 0;
int ret = 0;
int retry;
uint8_t bmc_location = 0;
uint8_t tbuf[2] = {0}, rdbuf[1] = {0};
uint8_t tlen = 2, rlen = 1;
int pfr_adress = CPLD_INTENT_CTRL_ADDR;
int mtd_no;
char rbuf[256], mtd_name[32], dev[16] = {0}, cmd[256] = {0};
char path[128];
string bmc_location_str;
string comp = component();
uint8_t intent_val_o = 0;
if ( fby3_common_get_bmc_location(&bmc_location) < 0 ) {
printf("Failed to initialize the fw-util\n");
return FW_STATUS_FAILURE;
}
if ( bmc_location == NIC_BMC ) {
bmc_location_str = "NIC Expansion";
snprintf(path, sizeof(path), NIC_CPLD_CTRL_BUS);
} else {
bmc_location_str = "baseboard";
snprintf(path, sizeof(path), BB_CPLD_CTRL_BUS);
}
// Check PFR provision status
i2cfd = open(path, O_RDWR);
if ( i2cfd < 0 ) {
syslog(LOG_WARNING, "%s() Failed to open %s", __func__, path);
return -1;
}
retry = 0;
tlen = 1;
tbuf[0] = UFM_STATUS_OFFSET;
while (retry < RETRY_TIME) {
ret = i2c_rdwr_msg_transfer(i2cfd, pfr_adress, tbuf, tlen, rdbuf, rlen);
if ( ret < 0 ) {
retry++;
msleep(100);
} else {
break;
}
}
if ( i2cfd > 0 ) close(i2cfd);
if (retry == RETRY_TIME) {
syslog(LOG_WARNING, "%s() Failed to do i2c_rdwr_msg_transfer, tlen=%d", __func__, tlen);
return -1;
}
if (!(rdbuf[0] & UFM_PROVISIONED_MSK)) {
printf("BMC is un-provisioned. Stopping the update! \n");
return -1;
}
tbuf[0] = CPLD_INTENT_CTRL_OFFSET;
printf("Start to update capsule...\n");
if (comp == "bmc_cap" || comp == "bmc_cap_rcvy") {
if ((fp = fopen("/proc/mtd", "r"))) {
while (fgets(rbuf, sizeof(rbuf), fp)) {
if ((sscanf(rbuf, "mtd%d: %*x %*x %s", &mtd_no, mtd_name) == 2) &&
!strcmp("\"stg-bmc\"", mtd_name)) {
sprintf(dev, "/dev/mtd%d", mtd_no);
break;
}
}
fclose(fp);
}
if (!dev[0] || !(fp = fopen(dev, "rb"))) {
printf("stg-bmc not found\n");
return FW_STATUS_FAILURE;
}
fclose(fp);
if (comp == "bmc_cap_rcvy") {
tbuf[1] = BMC_INTENT_RCVY_VALUE;
syslog(LOG_CRIT, "Updating BMC Capsule, Target to Recovery Region on %s. File: %s", bmc_location_str.c_str(), image.c_str());
} else {
tbuf[1] = BMC_INTENT_VALUE;
syslog(LOG_CRIT, "Updating BMC Capsule, Target to Active Region on %s. File: %s", bmc_location_str.c_str(), image.c_str());
}
snprintf(cmd, sizeof(cmd), "/usr/sbin/flashcp -v %s %s", image.c_str(), dev);
if (system(cmd) != 0) {
syslog(LOG_WARNING, "[%s] %s failed\n", __func__, cmd);
return FW_STATUS_FAILURE;
}
if (comp == "bmc_cap_rcvy") {
syslog(LOG_CRIT, "Updated BMC Capsule, Target to Recovery Region on %s. File: %s", bmc_location_str.c_str(), image.c_str());
} else {
syslog(LOG_CRIT, "Updated BMC Capsule, Target to Active Region on %s. File: %s", bmc_location_str.c_str(), image.c_str());
}
} else if (comp == "cpld_cap" || comp == "cpld_cap_rcvy") {
if ((fp = fopen("/proc/mtd", "r"))) {
while (fgets(rbuf, sizeof(rbuf), fp)) {
if ((sscanf(rbuf, "mtd%d: %*x %*x %s", &mtd_no, mtd_name) == 2) &&
!strcmp("\"stg-cpld\"", mtd_name)) {
sprintf(dev, "/dev/mtd%d", mtd_no);
break;
}
}
fclose(fp);
}
if (!dev[0] || !(fp = fopen(dev, "rb"))) {
printf("stg-cpld not found\n");
return FW_STATUS_FAILURE;
}
if (comp == "cpld_cap_rcvy") {
tbuf[1] = CPLD_INTENT_RCVY_VALUE;
syslog(LOG_CRIT, "Updating CPLD Capsule, Target to Recovery Region on %s. File: %s", bmc_location_str.c_str(), image.c_str());
} else {
tbuf[1] = CPLD_INTENT_VALUE;
syslog(LOG_CRIT, "Updating CPLD Capsule, Target to Active Region on %s. File: %s", bmc_location_str.c_str(), image.c_str());
}
snprintf(cmd, sizeof(cmd), "/usr/sbin/flashcp -v %s %s", image.c_str(), dev);
if (system(cmd) != 0) {
syslog(LOG_WARNING, "[%s] %s failed\n", __func__, cmd);
return FW_STATUS_FAILURE;
}
set_pfr_cap_ver_str(image, comp);
if (comp == "cpld_cap_rcvy") {
syslog(LOG_CRIT, "Updated CPLD Capsule, Target to Recovery Region on %s. File: %s", bmc_location_str.c_str(), image.c_str());
} else {
syslog(LOG_CRIT, "Updated CPLD Capsule, Target to Active Region on %s. File: %s", bmc_location_str.c_str(), image.c_str());
}
} else {
return FW_STATUS_NOT_SUPPORTED;
}
// Update Intent
i2cfd = open(path, O_RDWR);
if ( i2cfd < 0 ) {
syslog(LOG_WARNING, "%s() Failed to open %s", __func__, path);
return -1;
}
retry = 0;
tlen = 1;
while (retry < RETRY_TIME) {
ret = i2c_rdwr_msg_transfer(i2cfd, pfr_adress, tbuf, tlen, rdbuf, rlen);
if ( ret < 0 ) {
retry++;
msleep(100);
} else {
break;
}
}
intent_val_o = rdbuf[0];
if ( retry == RETRY_TIME ) {
if ( i2cfd > 0 ) close(i2cfd);
return -1;
}
tbuf[1] |= (intent_val_o | UPDATE_AT_RESET);
retry = 0;
tlen = 2;
while (retry < RETRY_TIME) {
ret = i2c_rdwr_msg_transfer(i2cfd, pfr_adress, tbuf, tlen, NULL, 0);
if ( ret < 0 ) {
retry++;
msleep(100);
} else {
break;
}
}
if ( i2cfd > 0 ) close(i2cfd);
if (retry == RETRY_TIME) {
syslog(LOG_WARNING, "%s() Failed to do i2c_rdwr_msg_transfer, tlen=%d", __func__, tlen);
return -1;
}
return 0;
}
int BmcCpldCapsuleComponent::update(string image) {
int ret;
string comp = component();
image_info image_sts = check_image(image, false);
if ( image_sts.result == false ) {
remove(image_sts.new_path.c_str());
return FW_STATUS_FAILURE;
}
//use the new path
image = image_sts.new_path;
ret = bmc_update_capsule(image);
//remove the tmp image
if (comp == "cpld_cap" || comp == "cpld_cap_rcvy") {
remove(image.c_str());
}
return ret;
}
int BmcCpldCapsuleComponent::fupdate(string image) {
int ret;
ret = bmc_update_capsule(image);
return ret;
}
int BmcCpldCapsuleComponent::print_version()
{
int ret, i2cfd = 0, retry=0;;
uint8_t tbuf[2] = {0}, rbuf[1] = {0};
uint8_t tlen = 1, rlen = 1;
char path[128];
string comp = component();
string ver("");
string comp_name;
// IF PFR active , get the recovery capsule firmware version
// Check PFR provision status
string i2cdev = "/dev/i2c-" + to_string(bus);
i2cfd = open(i2cdev.c_str(), O_RDWR);
if ( i2cfd < 0 ) {
syslog(LOG_WARNING, "%s() Failed to open %s", __func__, path);
return -1;
}
retry = 0;
tbuf[0] = UFM_STATUS_OFFSET;
tlen = 1;
while (retry < RETRY_TIME) {
ret = i2c_rdwr_msg_transfer(i2cfd, CPLD_INTENT_CTRL_ADDR, tbuf, tlen, rbuf, rlen);
if ( ret < 0 ) {
retry++;
msleep(100);
} else {
break;
}
}
if ( i2cfd > 0 ) close(i2cfd);
if (!(rbuf[0] & UFM_PROVISIONED_MSK)) {
return FW_STATUS_NOT_SUPPORTED;
}
try {
if (comp == "cpld_cap") {
comp_name = "BMC Staging Capsule";
if ( get_bmc_stg_cap_version(ver) < 0 ) {
throw "Error in getting the version of Staging Capsule";
}
cout << comp_name << " Version: " << ver << endl;
comp_name = "BMC CPLD Staging Capsule";
if ( get_pfr_recovery_ver_str(ver, comp) < 0 ) {
throw "Error in getting the version of Staging Capsule";
}
cout << comp_name << " Version: " << ver << endl;
} else if (comp == "cpld_cap_rcvy") {
comp_name = "BMC CPLD Recovery Capsule";
if ( get_pfr_recovery_ver_str(ver, comp) < 0 ) {
throw "Error in getting the version of BMC CPLD Recovery Capsule";
}
cout << comp_name << " Version: " << ver << endl;
} else {
return FW_STATUS_NOT_SUPPORTED;
}
} catch(string& err) {
printf("%s Version: NA (%s)\n", comp_name.c_str(), err.c_str());
}
return 0;
}