meta-facebook/meta-fby3/recipes-fby3/fw-util/files/bmc_cpld.cpp (299 lines of code) (raw):

#include <iostream> #include <sstream> #include <string> #include <cstdio> #include <cstring> #include <unistd.h> #include <fcntl.h> #include <algorithm> #include <sys/mman.h> #include <syslog.h> #include <openbmc/obmc-i2c.h> #include "server.h" #include "bmc_cpld.h" #include <facebook/fby3_common.h> using namespace std; image_info BmcCpldComponent::check_image(string image, bool force) { const string board_type[] = {"Unknown", "EVT", "DVT", "PVT", "MP"}; string flash_image = image; uint8_t bmc_location = 0; string fru_name = fru(); string slot_str = "slot"; string bmc_str = "bmc"; size_t slot_found = fru_name.find(slot_str); size_t bmc_found = fru_name.find(bmc_str); uint8_t slot_id = 0; int ret = -1; uint8_t board_rev = 0; uint8_t hsc_det = 0; int board_type_index = 0; bool board_rev_is_invalid = false; image_info image_sts = {"", false}; if ( fby3_common_get_bmc_location(&bmc_location) < 0 ) { printf("Failed to initialize the fw-util\n"); exit(EXIT_FAILURE); } //create a new tmp file 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 file 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; } uint8_t *memblock = new uint8_t [image_size + 1];//data_size + signed byte uint8_t signed_byte = 0; size_t r_b = read(fd_r, memblock, image_size + 1); size_t w_b = 0; //it's an old image if ( r_b == image_size ) { signed_byte = 0x0; } else if ( r_b == (image_size + 1) ) { signed_byte = memblock[image_size] & 0xff; r_b = r_b - 1; //only write data to tmp file } w_b = write(fd_w, memblock, r_b); //check size if ( r_b != w_b ) { cerr << "Cannot create the tmp file - " << image_sts.new_path << endl; cerr << "Read: " << r_b << " Write: " << w_b << endl; image_sts.result = false; } if ( force == false ) { // Read Board Revision from CPLD if ( ((bmc_location == BB_BMC) || (bmc_location == DVT_BB_BMC)) && (bmc_found != string::npos)) { if ( fby3_common_get_bb_board_rev(&board_rev) ) { cout << "Failed to get bb board rev" << endl; return image_sts; } // respin board, Need to process BOARD_REV through HSC_DETECT, keeping the original logic work if ( fby3_common_get_hsc_bb_detect(&hsc_det) ) { cout << "Failed to get bb board rev" << endl; return image_sts; } if ( hsc_det == HSC_DET_ADM1278 ) { // old board, BOARD_REV_ID3 is floating. board_rev &= 0x7; } else { // new respin board is the MP stage, // rise bit3 to keep "if (board_type_index < CPLD_BOARD_PVT_REV)" work. board_rev |= 0x8; } } else if (slot_found != string::npos) { bic_gpio_t gpio = {0}; slot_id = fru_name.at(4) - '0'; if ( fby3_common_get_sb_board_rev(slot_id, &board_rev) ) { cout << "Failed to get sb board rev" << endl; return image_sts; } // respin board, Need to process BOARD_REV through HSC_DETECT, keeping the original logic work ret = bic_get_gpio(slot_id, &gpio, NONE_INTF); if ( ret < 0 ) { printf("%s() bic_get_gpio returns %d\n", __func__, ret); return image_sts; } hsc_det |= ((BIT_VALUE(gpio, 77)) << 0); // 77 HSC_DETECT0 hsc_det |= ((BIT_VALUE(gpio, 78)) << 1); // 78 HSC_DETECT1 hsc_det |= ((BIT_VALUE(gpio, 79)) << 2); // 79 HSC_DETECT2 if ( hsc_det == HSC_DET_ADM1278 ) { // old board, BOARD_REV_ID3 is floating. board_rev &= 0x7; } else { // new respin board is the MP stage, // rise bit3 to keep "if (board_type_index < CPLD_BOARD_PVT_REV)" work. board_rev |= 0x8; } } board_type_index = board_rev - 1; if (board_type_index < 0) { board_type_index = 0; } // PVT & MP firmware could be used in common if (board_type_index < CPLD_BOARD_PVT_REV) { if (REVISION_ID(signed_byte) != board_type_index) { board_rev_is_invalid = true; } } else { if (REVISION_ID(signed_byte) < CPLD_BOARD_PVT_REV) { board_rev_is_invalid = true; } } //CPLD is located on class 2(NIC_EXP) if ( bmc_location == NIC_BMC ) { if ( (COMPONENT_ID(signed_byte) == NICEXP) && (bmc_found != string::npos) ) { image_sts.result = true; } else if ( !board_rev_is_invalid && (COMPONENT_ID(signed_byte) == BICDL) && (slot_found != string::npos)) { image_sts.result = true; } else { if (board_rev_is_invalid && (slot_found != string::npos)) { cout << "To prevent this update on " << fru_name <<", please use the f/w of " << board_type[board_type_index].c_str() <<" on the " << board_type[board_type_index].c_str() <<" system." << endl; cout << "To force the update, please use the --force option." << endl; } cout << "image is not a valid CPLD image for " << fru_name << endl; } } else if ( (bmc_location == BB_BMC) || (bmc_location == DVT_BB_BMC) ) { if ( !board_rev_is_invalid && (COMPONENT_ID(signed_byte) == BICBB) && (bmc_found != string::npos) ) { image_sts.result = true; } else if ( !board_rev_is_invalid && (COMPONENT_ID(signed_byte) == BICDL) && (slot_found != string::npos) ) { image_sts.result = true; } else { if (board_rev_is_invalid) { cout << "To prevent this update on " << fru_name <<", please use the f/w of " << board_type[board_type_index].c_str() <<" on the " << board_type[board_type_index].c_str() <<" system." << endl; cout << "To force the update, please use the --force option." << endl; } 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 BmcCpldComponent::get_ver_str(string& s) { int ret = 0; char ver[32] = {0}; uint32_t ver_reg = ON_CHIP_FLASH_USER_VER; uint8_t tbuf[4] = {0x00}; uint8_t rbuf[4] = {0x00}; uint8_t tlen = 4; uint8_t rlen = 4; int i2cfd = 0; memcpy(tbuf, (uint8_t *)&ver_reg, tlen); reverse(tbuf, tbuf + 4); 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, addr) < 0) { printf("Failed to talk to slave@0x%02X\n", addr); } else { ret = i2c_rdwr_msg_transfer(i2cfd, addr << 1, 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 BmcCpldComponent::print_version() { string ver(""); string fru_name = fru(); size_t slot_found = fru_name.find("slot"); try { // Print CPLD Version if (slot_found != string::npos) { uint8_t slot_id = fru_name.at(4) - '0'; Server server(slot_id, fru_name); fru_name = "SB"; server.ready(); } else { transform(fru_name.begin(), fru_name.end(), fru_name.begin(), ::toupper); } if ( get_ver_str(ver) < 0 ) { throw "Error in getting the version of " + fru_name; } cout << fru_name << " CPLD Version: " << ver << endl; } catch(string& err) { printf("%s CPLD Version: NA (%s)\n", fru_name.c_str(), err.c_str()); } return 0; } void BmcCpldComponent::get_version(json& j) { string ver(""); string fru_name = fru(); size_t slot_found = fru_name.find("slot"); try { if (slot_found != string::npos) { uint8_t slot_id = fru_name.at(4) - '0'; Server server(slot_id, fru_name); fru_name = "SB"; server.ready(); } if ( get_ver_str(ver) < 0 ) { throw "Error in getting the version of " + fru_name; } j["VERSION"] = ver; } catch(string& err) { if ( err.find("empty") != string::npos ) j["VERSION"] = "not_present"; else j["VERSION"] = "error_returned"; } } int BmcCpldComponent::update_cpld(string image) { int ret = 0; char key[32] = {0}; uint8_t bmc_location = 0; string bmc_location_str; string image_tmp; size_t pos = image.find("-tmp"); image_tmp = image.substr(0, pos); string fru_name = fru(); string slot_str = "slot"; size_t slot_found = fru_name.find(slot_str); 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"; } else { bmc_location_str = "baseboard"; } if (slot_found != string::npos) { bmc_location_str = fru_name+ " " + "SB"; //Check Server Board is Ready try { uint8_t slot_id = fru_name.at(4) - '0'; Server server(slot_id, fru_name); server.ready(); } catch(string& err) { printf("%s\n", err.c_str()); return FW_STATUS_NOT_SUPPORTED; } } syslog(LOG_CRIT, "Updating CPLD on %s. File: %s", bmc_location_str.c_str(), image_tmp.c_str()); if (cpld_intf_open(pld_type, INTF_I2C, &attr)) { printf("Cannot open i2c!\n"); ret = FW_STATUS_FAILURE; } else { //TODO: need to update 2 CFMs ret = cpld_program((char *)image.c_str(), key, false); cpld_intf_close(); if ( ret < 0 ) { printf("Error Occur at updating CPLD FW!\n"); } } syslog(LOG_CRIT, "Updated CPLD on %s. File: %s. Result: %s", bmc_location_str.c_str(), image_tmp.c_str(), (ret < 0)?"Fail":"Success"); return ret; } void BmcCpldComponent::check_module() { string ver(""); if (get_ver_str(ver) < 0 || ver.length() < VER_STR_LEN) { cout << "Fail to get current CPLD module: use default settings" << endl; return; } if (ver[4] == MAX10M08_VER_CHAR) { attr.start_addr = MAX10M08_CFM1_START_ADDR; attr.end_addr = MAX10M08_CFM1_END_ADDR; image_size = MAX10M08_CFM1_END_ADDR - MAX10M08_CFM1_START_ADDR + 1; } return; } int BmcCpldComponent::update(string image) { int ret = 0; image_info image_sts; check_module(); 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 = update_cpld(image); //remove the tmp file remove(image.c_str()); return ret; } int BmcCpldComponent::fupdate(string image) { int ret = 0; image_info image_sts; check_module(); image_sts = check_image(image, true); image = image_sts.new_path; ret = update_cpld(image); //remove the tmp file remove(image.c_str()); return ret; }