blob: db323cada29142ee75d233114b2fcb7f12bc3d8e [file] [log] [blame]
extern "C"
{
#include <libpdbg.h>
}
#include "attributes_info.H"
#include "extensions/phal/common_utils.hpp"
#include "extensions/phal/create_pel.hpp"
#include "extensions/phal/phal_error.hpp"
#include "util.hpp"
#include <fmt/format.h>
#include <libekb.H>
#include <ext_interface.hpp>
#include <phosphor-logging/log.hpp>
#include <registration.hpp>
namespace openpower
{
namespace phal
{
using namespace phosphor::logging;
/**
* @brief Select BOOT SEEPROM and Measurement SEEPROM(PRIMARY/BACKUP) on POWER
* processor position 0/1 depending on boot count before kicking off
* the boot.
*
* @return void
*/
void selectBootSeeprom()
{
struct pdbg_target* procTarget;
ATTR_BACKUP_SEEPROM_SELECT_Enum bkpSeePromSelect;
ATTR_BACKUP_MEASUREMENT_SEEPROM_SELECT_Enum bkpMeaSeePromSelect;
pdbg_for_each_class_target("proc", procTarget)
{
if (!isPrimaryProc(procTarget))
{
continue;
}
// Choose seeprom side to boot from based on boot count
if (getBootCount() > 0)
{
log<level::INFO>("Setting SBE seeprom side to 0",
entry("SBE_SIDE_SELECT=%d",
ENUM_ATTR_BACKUP_SEEPROM_SELECT_PRIMARY));
bkpSeePromSelect = ENUM_ATTR_BACKUP_SEEPROM_SELECT_PRIMARY;
bkpMeaSeePromSelect =
ENUM_ATTR_BACKUP_MEASUREMENT_SEEPROM_SELECT_PRIMARY;
}
else
{
log<level::INFO>("Setting SBE seeprom side to 1",
entry("SBE_SIDE_SELECT=%d",
ENUM_ATTR_BACKUP_SEEPROM_SELECT_SECONDARY));
bkpSeePromSelect = ENUM_ATTR_BACKUP_SEEPROM_SELECT_SECONDARY;
bkpMeaSeePromSelect =
ENUM_ATTR_BACKUP_MEASUREMENT_SEEPROM_SELECT_SECONDARY;
}
// Set the Attribute as per bootcount policy for boot seeprom
if (DT_SET_PROP(ATTR_BACKUP_SEEPROM_SELECT, procTarget,
bkpSeePromSelect))
{
log<level::ERR>(
"Attribute [ATTR_BACKUP_SEEPROM_SELECT] set failed");
throw std::runtime_error(
"Attribute [ATTR_BACKUP_SEEPROM_SELECT] set failed");
}
// Set the Attribute as per bootcount policy for measurement seeprom
if (DT_SET_PROP(ATTR_BACKUP_MEASUREMENT_SEEPROM_SELECT, procTarget,
bkpMeaSeePromSelect))
{
log<level::ERR>(
"Attribute [ATTR_BACKUP_MEASUREMENT_SEEPROM_SELECT] set "
"failed");
throw std::runtime_error(
"Attribute [ATTR_BACKUP_MEASUREMENT_SEEPROM_SELECT] set "
"failed");
}
}
}
/**
* @brief Read the HW Level from VPD and set CLK NE termination site
* Note any failure in this function will result startHost failure.
*/
void setClkNETerminationSite()
{
// Get Motherborad VINI Recored "HW" keyword
constexpr auto objPath =
"/xyz/openbmc_project/inventory/system/chassis/motherboard";
constexpr auto kwdVpdInf = "com.ibm.ipzvpd.VINI";
constexpr auto hwKwd = "HW";
auto bus = sdbusplus::bus::new_default();
std::string service = util::getService(bus, objPath, kwdVpdInf);
auto properties = bus.new_method_call(
service.c_str(), objPath, "org.freedesktop.DBus.Properties", "Get");
properties.append(kwdVpdInf);
properties.append(hwKwd);
// Store "HW" Keyword data.
std::variant<std::vector<uint8_t>> val;
try
{
auto result = bus.call(properties);
result.read(val);
}
catch (const sdbusplus::exception::exception& e)
{
log<level::ERR>("Get HW Keyword read from VINI Failed");
throw std::runtime_error("Get HW Keyword read from VINI Failed");
}
auto hwData = std::get<std::vector<uint8_t>>(val);
//"HW" Keyword size is 2 as per VPD spec.
constexpr auto hwKwdSize = 2;
if (hwKwdSize != hwData.size())
{
log<level::ERR>(
fmt::format("Incorrect VINI records HW Keyword data size({})",
hwData.size())
.c_str());
throw std::runtime_error("Incorrect VINI records HW Keyword data size");
}
log<level::DEBUG>(fmt::format("VINI Records HW[0]:{} HW[1]:{}",
hwData.at(0), hwData.at(1))
.c_str());
// VINI Record "HW" keyword's Byte 0's MSB bit indicates
// proc or planar type need to choose.
constexpr uint8_t SYS_CLK_NE_TERMINATION_ON_MASK = 0x80;
ATTR_SYS_CLK_NE_TERMINATION_SITE_Type clockTerm =
ENUM_ATTR_SYS_CLK_NE_TERMINATION_SITE_PLANAR;
if (SYS_CLK_NE_TERMINATION_ON_MASK & hwData.at(0))
{
clockTerm = ENUM_ATTR_SYS_CLK_NE_TERMINATION_SITE_PROC;
}
// update all the processor attributes
struct pdbg_target* procTarget;
pdbg_for_each_class_target("proc", procTarget)
{
if (DT_SET_PROP(ATTR_SYS_CLK_NE_TERMINATION_SITE, procTarget,
clockTerm))
{
log<level::ERR>(
"Attribute ATTR_SYS_CLK_NE_TERMINATION_SITE set failed");
throw std::runtime_error(
"Attribute ATTR_SYS_CLK_NE_TERMINATION_SITE set failed");
}
}
}
/**
* @brief Starts the self boot engine on POWER processor position 0
* to kick off a boot.
* @return void
*/
void startHost(enum ipl_type iplType = IPL_TYPE_NORMAL)
{
try
{
phal_init();
ipl_set_type(iplType);
if (iplType == IPL_TYPE_NORMAL)
{
// Update SEEPROM side only for NORMAL boot
selectBootSeeprom();
}
setClkNETerminationSite();
}
catch (const std::exception& ex)
{
log<level::ERR>("Exception raised during ipl initialisation",
entry("EXCEPTION=%s", ex.what()));
openpower::pel::createPEL("org.open_power.PHAL.Error.Boot");
openpower::pel::detail::processBootError(false);
throw std::runtime_error("IPL initialization failed");
}
// To clear trace if success
openpower::pel::detail::processBootError(true);
// callback method will be called upon failure which will create the PEL
int rc = ipl_run_major(0);
if (rc > 0)
{
log<level::ERR>("step 0 failed to start the host");
throw std::runtime_error("Failed to execute host start boot step");
}
}
/**
* @brief Starts the reboot with type memory preserving reboot.
* @return void
*/
void startHostMpReboot()
{
// set ipl type as mpipl
startHost(IPL_TYPE_MPIPL);
}
/**
* @brief Starts the normal boot type.
* @return void
*/
void startHostNormal()
{
startHost(IPL_TYPE_NORMAL);
}
REGISTER_PROCEDURE("startHost", startHostNormal)
REGISTER_PROCEDURE("startHostMpReboot", startHostMpReboot)
} // namespace phal
} // namespace openpower