blob: 27b6b79363191933eda97084183e478c41505476 [file] [log] [blame]
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "util.hpp"
#include <nlohmann/json.hpp>
#include <phosphor-logging/elog-errors.hpp>
#include <stdplus/print.hpp>
#include <xyz/openbmc_project/Common/error.hpp>
#include <cstdint>
#include <cstdio>
#include <filesystem>
#include <fstream>
#include <regex>
#include <string>
#include <tuple>
#include <vector>
namespace google
{
namespace ipmi
{
namespace fs = std::filesystem;
using namespace phosphor::logging;
using InternalFailure =
sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
nlohmann::json parseConfig(const std::string& file)
{
std::ifstream jsonFile(file);
if (!jsonFile.is_open())
{
log<level::ERR>("Entity association JSON file not found");
elog<InternalFailure>();
}
auto data = nlohmann::json::parse(jsonFile, nullptr, false);
if (data.is_discarded())
{
log<level::ERR>("Entity association JSON parser failure");
elog<InternalFailure>();
}
return data;
}
std::string readPropertyFile(const std::string& fileName)
{
std::ifstream ifs(fileName);
std::string contents;
if (!ifs.is_open())
{
auto msg = std::string("Unable to open file ") + fileName.c_str();
log<level::DEBUG>(msg.c_str());
}
else
{
if (ifs >> contents)
{
// If the last character is a null terminator; remove it.
if (!contents.empty())
{
const char& back = contents.back();
if (back == '\0')
contents.pop_back();
}
return contents;
}
else
{
stdplus::print(stderr, "Unable to read file {}.\n", fileName);
}
}
return "";
}
std::vector<std::tuple<std::uint32_t, std::string>> buildPcieMap()
{
std::vector<std::tuple<std::uint32_t, std::string>> pcie_i2c_map;
// Build a vector with i2c bus to pcie slot mapping.
// Iterate through all the devices under "/sys/bus/i2c/devices".
for (const auto& i2c_dev : fs::directory_iterator("/sys/bus/i2c/devices"))
{
std::string i2c_dev_path = i2c_dev.path();
std::smatch i2c_dev_string_number;
std::regex e("(i2c-)(\\d+)");
// Check if the device has "i2c-" in its path.
if (std::regex_search(i2c_dev_path, i2c_dev_string_number, e))
{
// Check if the i2c device has "pcie-slot" file under "of-node" dir.
std::string pcie_slot_path = i2c_dev_path + "/of_node/pcie-slot";
std::string pcie_slot;
// Read the "pcie-slot" name from the "pcie-slot" file.
pcie_slot = readPropertyFile(pcie_slot_path);
if (pcie_slot.empty())
{
continue;
}
std::string pcie_slot_name;
std::string pcie_slot_full_path;
// Append the "pcie-slot" name to dts base.
pcie_slot_full_path.append("/proc/device-tree");
pcie_slot_full_path.append(pcie_slot);
// Read the "label" which contains the pcie slot name.
pcie_slot_full_path.append("/label");
pcie_slot_name = readPropertyFile(pcie_slot_full_path);
if (pcie_slot_name.empty())
{
continue;
}
// Get the i2c bus number from the i2c device path.
std::uint32_t i2c_bus_number =
i2c_dev_string_number[2].matched
? std::stoi(i2c_dev_string_number[2])
: 0;
// Store the i2c bus number and the pcie slot name in the vector.
pcie_i2c_map.push_back(
std::make_tuple(i2c_bus_number, pcie_slot_name));
}
}
return pcie_i2c_map;
}
} // namespace ipmi
} // namespace google