Handle CPU Module and FRU in write VPD
Test-
1. Using vpd-tool
./vpd-tool --readKeyword --object /system/chassis/motherboard --record VINI --keyword SN
{
"/system/chassis/motherboard": {
"SN": "YL2E2D010000"
}
}
./vpd-tool --writeKeyword --object /system/chassis/motherboard --record VINI --keyword SN --value 0x303030
./vpd-tool --readKeyword --object /system/chassis/motherboard --record VINI --keyword SN {
"/system/chassis/motherboard": {
"SN": "000E2D010000"
}
}
COM interface-
Change-Id: I39ee0448483be581da254f5633b0817637292dff
-------------
.SN property ay 12 48 48 48 69 50 68 48 49 48 48 48 48 emits-change writable
Common Interface-
----------------
xyz.openbmc_project.Inventory.Decorator.Asset interface - - -
.SerialNumber property s "000E2D010000" emits-change writable
sys path updated-
--------
00000110 35 53 4e 0c 30 30 30 45 32 44 30 31 30 30 30 30 |5SN.000E2D010000|
2. Tested on simics with spi driver supported image for 1 DCM
verified CPUs and other FRUs to work as expected.
1- busctl call WriteKeyword ossay "/system/chassis/motherboard/cpu0" "VINI" "DR" 1 65
Updating CI, so updated cpu0, cpu1 and spi2 vpd.
2- busctl call WriteKeyword ossay "/system/chassis/motherboard/cpu1" "VINI" "DR" 1 66
Updating CI, so updated cpu0, cpu1 and spi2 vpd.
3- busctl call WriteKeyword ossay "/system/chassis/motherboard/cpu0" "VINI" "CC" 1 67
Not a CI, so only cpu0 and spi2 vpd updated.
4- busctl call WriteKeyword ossay "/system/chassis/motherboard/cpu1" "VINI" "CC" 1 67
Not a CI, so only cpu1 and spi6 vpd updated.
cpu1 updated 1 Byte data of DR (7)-
busctl call WriteKeyword ossay "/system/chassis/motherboard/cpu1" "VINI" "DR" 1 55
Read file info at spi2.0/spi2.00/nvmem offset 0x30000-
000001a0 04 56 49 4e 49 44 52 10 37 20 57 41 59 20 20 50 |.VINIDR.7 WAY P| <--DR updated 1 Byte
Change-Id: I5e99c1ac4e09b2d0e05be18a10d1d50eba22fea2
Signed-off-by: Alpana Kumari <alpankum@in.ibm.com>
diff --git a/vpd-manager/editor_impl.cpp b/vpd-manager/editor_impl.cpp
index b9104f0..e5d698a 100644
--- a/vpd-manager/editor_impl.cpp
+++ b/vpd-manager/editor_impl.cpp
@@ -95,7 +95,8 @@
#else
// update data in EEPROM as well. As we will not write complete file back
- vpdFileStream.seekg(thisRecord.kwDataOffset, std::ios::beg);
+ vpdFileStream.seekp(offset + thisRecord.kwDataOffset, std::ios::beg);
+
iteratorToNewdata = kwdData.cbegin();
std::copy(iteratorToNewdata, end,
std::ostreambuf_iterator<char>(vpdFileStream));
@@ -186,7 +187,7 @@
std::advance(end, thisRecord.recECCLength);
#ifndef ManagerTest
- vpdFileStream.seekp(thisRecord.recECCoffset, std::ios::beg);
+ vpdFileStream.seekp(offset + thisRecord.recECCoffset, std::ios::beg);
std::copy(itrToRecordECC, end,
std::ostreambuf_iterator<char>(vpdFileStream));
#endif
@@ -352,30 +353,62 @@
{
// by default inherit property is true
bool isInherit = true;
+ bool isInheritEI = true;
+ bool isCpuModuleOnly = false;
if (singleInventory.find("inherit") != singleInventory.end())
{
isInherit = singleInventory["inherit"].get<bool>();
}
+ if (singleInventory.find("inheritEI") != singleInventory.end())
+ {
+ isInheritEI = singleInventory["inheritEI"].get<bool>();
+ }
+
+ // "type" exists only in CPU module and FRU
+ if (singleInventory.find("type") != singleInventory.end())
+ {
+ if (singleInventory["type"] == "moduleOnly")
+ {
+ isCpuModuleOnly = true;
+ }
+ }
+
if (isInherit)
{
// update com interface
- makeDbusCall<Binary>(
- (INVENTORY_PATH +
- singleInventory["inventoryPath"].get<std::string>()),
- (IPZ_INTERFACE + (std::string) "." + thisRecord.recName),
- thisRecord.recKWd, thisRecord.kwdUpdatedData);
+ // For CPU- update com interface only when isCI true
+ if ((!isCpuModuleOnly) || (isCpuModuleOnly && isCI))
+ {
+ makeDbusCall<Binary>(
+ (INVENTORY_PATH +
+ singleInventory["inventoryPath"].get<std::string>()),
+ (IPZ_INTERFACE + (std::string) "." + thisRecord.recName),
+ thisRecord.recKWd, thisRecord.kwdUpdatedData);
+ }
// process Common interface
processAndUpdateCI(singleInventory["inventoryPath"]
.get_ref<const nlohmann::json::string_t&>());
}
- // process extra interfaces
- processAndUpdateEI(singleInventory,
- singleInventory["inventoryPath"]
- .get_ref<const nlohmann::json::string_t&>());
+ if (isInheritEI)
+ {
+ if (isCpuModuleOnly)
+ {
+ makeDbusCall<Binary>(
+ (INVENTORY_PATH +
+ singleInventory["inventoryPath"].get<std::string>()),
+ (IPZ_INTERFACE + (std::string) "." + thisRecord.recName),
+ thisRecord.recKWd, thisRecord.kwdUpdatedData);
+ }
+
+ // process extra interfaces
+ processAndUpdateEI(singleInventory,
+ singleInventory["inventoryPath"]
+ .get_ref<const nlohmann::json::string_t&>());
+ }
}
}
@@ -446,29 +479,139 @@
}
}
+string EditorImpl::getSysPathForThisFruType(const string& moduleObjPath,
+ const string& fruType)
+{
+ string fruVpdPath;
+
+ // get all FRUs list
+ for (const auto& eachFru : jsonFile["frus"].items())
+ {
+ bool moduleObjPathMatched = false;
+ bool expectedFruFound = false;
+
+ for (const auto& eachInventory : eachFru.value())
+ {
+ const auto& thisObjectPath = eachInventory["inventoryPath"];
+
+ // "type" exists only in CPU module and FRU
+ if (eachInventory.find("type") != eachInventory.end())
+ {
+ // If inventory type is fruAndModule then set flag
+ if (eachInventory["type"] == fruType)
+ {
+ expectedFruFound = true;
+ }
+ }
+
+ if (thisObjectPath == moduleObjPath)
+ {
+ moduleObjPathMatched = true;
+ }
+ }
+
+ // If condition satisfies then collect this sys path and exit
+ if (expectedFruFound && moduleObjPathMatched)
+ {
+ fruVpdPath = eachFru.key();
+ break;
+ }
+ }
+
+ return fruVpdPath;
+}
+
+void EditorImpl::getVpdPathForCpu()
+{
+ isCI = false;
+ // keep a backup In case we need it later
+ inventory::Path vpdFilePathBackup = vpdFilePath;
+
+ // TODO 1:Temp hardcoded list. create it dynamically.
+ std::vector<std::string> commonIntVINIKwds = {"PN", "SN", "DR"};
+ std::vector<std::string> commonIntVR10Kwds = {"DC"};
+ std::unordered_map<std::string, std::vector<std::string>>
+ commonIntRecordsList = {{"VINI", commonIntVINIKwds},
+ {"VR10", commonIntVR10Kwds}};
+
+ // If requested Record&Kw is one among CI, then update 'FRU' type sys
+ // path, SPI2
+ unordered_map<std::string, vector<string>>::const_iterator isCommonInt =
+ commonIntRecordsList.find(thisRecord.recName);
+
+ if ((isCommonInt != commonIntRecordsList.end()) &&
+ (find(isCommonInt->second.begin(), isCommonInt->second.end(),
+ thisRecord.recKWd) != isCommonInt->second.end()))
+ {
+ isCI = true;
+ vpdFilePath = getSysPathForThisFruType(objPath, "fruAndModule");
+ }
+ else
+ {
+ for (const auto& eachFru : jsonFile["frus"].items())
+ {
+ for (const auto& eachInventory : eachFru.value())
+ {
+ if (eachInventory.find("type") != eachInventory.end())
+ {
+ const auto& thisObjectPath = eachInventory["inventoryPath"];
+ if ((eachInventory["type"] == "moduleOnly") &&
+ (eachInventory.value("inheritEI", true)) &&
+ (thisObjectPath == static_cast<string>(objPath)))
+ {
+ vpdFilePath = eachFru.key();
+ }
+ }
+ }
+ }
+ }
+ // If it is not a CPU fru then go ahead with default vpdFilePath from
+ // fruMap
+ if (vpdFilePath.empty())
+ {
+ vpdFilePath = vpdFilePathBackup;
+ }
+}
+
void EditorImpl::updateKeyword(const Binary& kwdData)
{
-
+ offset = 0;
#ifndef ManagerTest
+
+ getVpdPathForCpu();
+
+ uint32_t offset = 0;
+ // check if offset present?
+ for (const auto& item : jsonFile["frus"][vpdFilePath])
+ {
+ if (item.find("offset") != item.end())
+ {
+ offset = item["offset"];
+ }
+ }
+
+ // TODO: Figure out a better way to get max possible VPD size.
+ Binary completeVPDFile;
+ completeVPDFile.resize(65504);
vpdFileStream.open(vpdFilePath,
std::ios::in | std::ios::out | std::ios::binary);
- if (!vpdFileStream)
- {
- throw std::runtime_error("unable to open vpd file to edit");
- }
+ vpdFileStream.seekg(offset, ios_base::cur);
+ vpdFileStream.read(reinterpret_cast<char*>(&completeVPDFile[0]), 65504);
+ completeVPDFile.resize(vpdFileStream.gcount());
+ vpdFileStream.clear(std::ios_base::eofbit);
- Binary completeVPDFile((std::istreambuf_iterator<char>(vpdFileStream)),
- std::istreambuf_iterator<char>());
vpdFile = completeVPDFile;
+
#else
+
Binary completeVPDFile = vpdFile;
+
#endif
if (vpdFile.empty())
{
throw std::runtime_error("Invalid File");
}
-
auto iterator = vpdFile.cbegin();
std::advance(iterator, IPZ_DATA_START);
diff --git a/vpd-manager/editor_impl.hpp b/vpd-manager/editor_impl.hpp
index b3d24f7..d4d5598 100644
--- a/vpd-manager/editor_impl.hpp
+++ b/vpd-manager/editor_impl.hpp
@@ -65,9 +65,10 @@
* @param[in] path - Path to the vpd file
*/
EditorImpl(const inventory::Path& path, const nlohmann::json& json,
- const std::string& record, const std::string& kwd) :
+ const std::string& record, const std::string& kwd,
+ const sdbusplus::message::object_path& inventoryPath) :
vpdFilePath(path),
- jsonFile(json), thisRecord(record, kwd)
+ objPath(inventoryPath), jsonFile(json), thisRecord(record, kwd)
{
}
@@ -151,11 +152,17 @@
const std::string& property, const std::variant<T>& data);
// path to the VPD file to edit
- const inventory::Path vpdFilePath;
+ inventory::Path vpdFilePath;
+
+ // inventory path of fru/module to update keyword
+ const inventory::Path objPath;
// stream to perform operation on file
std::fstream vpdFileStream;
+ // offset to get vpd data from EEPROM
+ uint32_t offset;
+
// file to store parsed json
const nlohmann::json jsonFile;
@@ -181,6 +188,25 @@
Binary vpdFile;
+ // If requested Interface is common Interface
+ bool isCI;
+
+ /** @brief This API will be used to find out Parent FRU of Module/CPU
+ *
+ * @param[in] - moduleObjPath, object path of that FRU
+ * @param[in] - fruType, Type of Parent FRU
+ * for Module/CPU Parent Type- FruAndModule
+ *
+ * @return returns vpd file path of Parent Fru of that Module
+ */
+ std::string getSysPathForThisFruType(const std::string& moduleObjPath,
+ const std::string& fruType);
+
+ /** @brief This API will search for correct EEPROM path for asked CPU
+ * and will init vpdFilePath
+ */
+ void getVpdPathForCpu();
+
}; // class EditorImpl
} // namespace editor
diff --git a/vpd-manager/manager.cpp b/vpd-manager/manager.cpp
index 3d8462c..717a83a 100644
--- a/vpd-manager/manager.cpp
+++ b/vpd-manager/manager.cpp
@@ -80,11 +80,16 @@
.get_ref<const nlohmann::json::string_t&>(),
std::make_pair(itemFRUS.key(), isMotherboard));
- fruLocationCode.emplace(
- itemEEPROM["extraInterfaces"][LOCATION_CODE_INF]["LocationCode"]
- .get_ref<const nlohmann::json::string_t&>(),
- itemEEPROM["inventoryPath"]
- .get_ref<const nlohmann::json::string_t&>());
+ if (itemEEPROM["extraInterfaces"].find(LOCATION_CODE_INF) !=
+ itemEEPROM["extraInterfaces"].end())
+ {
+ fruLocationCode.emplace(
+ itemEEPROM["extraInterfaces"][LOCATION_CODE_INF]
+ ["LocationCode"]
+ .get_ref<const nlohmann::json::string_t&>(),
+ itemEEPROM["inventoryPath"]
+ .get_ref<const nlohmann::json::string_t&>());
+ }
}
}
}
@@ -103,7 +108,7 @@
inventory::Path vpdFilePath = frus.find(path)->second.first;
// instantiate editor class to update the data
- EditorImpl edit(vpdFilePath, jsonFile, recordName, keyword);
+ EditorImpl edit(vpdFilePath, jsonFile, recordName, keyword, path);
edit.updateKeyword(value);
// if it is a motehrboard FRU need to check for location expansion