blob: eebc84e7a50c36297cf2050f54c26dddd8c9ce8d [file] [log] [blame]
Patrick Ventureab650002019-03-16 09:08:47 -07001#include "util.hpp"
2
Patrick Venture3fb74292019-03-16 11:32:16 -07003#include <cstdint>
Patrick Venture8d5c9ce2019-03-16 11:20:12 -07004#include <cstdio>
Patrick Venture3fb74292019-03-16 11:32:16 -07005#include <filesystem>
Patrick Ventureab650002019-03-16 09:08:47 -07006#include <fstream>
7#include <nlohmann/json.hpp>
8#include <phosphor-logging/elog-errors.hpp>
Patrick Venture3fb74292019-03-16 11:32:16 -07009#include <regex>
Patrick Ventureab650002019-03-16 09:08:47 -070010#include <string>
Patrick Venture3fb74292019-03-16 11:32:16 -070011#include <tuple>
12#include <vector>
Patrick Ventureab650002019-03-16 09:08:47 -070013#include <xyz/openbmc_project/Common/error.hpp>
14
15namespace google
16{
17namespace ipmi
18{
Patrick Venture3fb74292019-03-16 11:32:16 -070019namespace fs = std::filesystem;
Patrick Ventureab650002019-03-16 09:08:47 -070020using namespace phosphor::logging;
21using InternalFailure =
22 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
23
24nlohmann::json parseConfig(const std::string& file)
25{
26 std::ifstream jsonFile(file);
27 if (!jsonFile.is_open())
28 {
29 log<level::ERR>("Entity association JSON file not found");
30 elog<InternalFailure>();
31 }
32
33 auto data = nlohmann::json::parse(jsonFile, nullptr, false);
34 if (data.is_discarded())
35 {
36 log<level::ERR>("Entity association JSON parser failure");
37 elog<InternalFailure>();
38 }
39
40 return data;
41}
42
Patrick Venture8d5c9ce2019-03-16 11:20:12 -070043std::string readPropertyFile(const std::string& fileName)
44{
45 std::ifstream ifs(fileName);
46 std::string contents;
47
48 if (!ifs.is_open())
49 {
50 std::fprintf(stderr, "Unable to open file %s.\n", fileName.c_str());
51 }
52 else
53 {
54 if (ifs >> contents)
55 {
56 // If the last character is a null terminator; remove it.
57 if (!contents.empty())
58 {
59 char const& back = contents.back();
60 if (back == '\0')
61 contents.pop_back();
62 }
63
64 return contents;
65 }
66 else
67 {
68 std::fprintf(stderr, "Unable to read file %s.\n", fileName.c_str());
69 }
70 }
71
72 return "";
73}
74
Patrick Venture3fb74292019-03-16 11:32:16 -070075std::vector<std::tuple<std::uint32_t, std::string>> buildPcieMap()
76{
77 std::vector<std::tuple<std::uint32_t, std::string>> pcie_i2c_map;
78
79 // Build a vector with i2c bus to pcie slot mapping.
80 // Iterate through all the devices under "/sys/bus/i2c/devices".
81 for (const auto& i2c_dev : fs::directory_iterator("/sys/bus/i2c/devices"))
82 {
83 std::string i2c_dev_path = i2c_dev.path();
84 std::smatch i2c_dev_string_number;
85 std::regex e("(i2c-)(\\d+)");
86
87 // Check if the device has "i2c-" in its path.
88 if (std::regex_search(i2c_dev_path, i2c_dev_string_number, e))
89 {
90 // Check if the i2c device has "pcie-slot" file under "of-node" dir.
91 std::string pcie_slot_path = i2c_dev_path + "/of_node/pcie-slot";
92 std::string pcie_slot;
93
94 // Read the "pcie-slot" name from the "pcie-slot" file.
95 pcie_slot = readPropertyFile(pcie_slot_path);
96 if (pcie_slot.empty())
97 {
98 continue;
99 }
100 std::string pcie_slot_name;
101 std::string pcie_slot_full_path;
102
103 // Append the "pcie-slot" name to dts base.
104 pcie_slot_full_path.append("/proc/device-tree");
105 pcie_slot_full_path.append(pcie_slot);
106
107 // Read the "label" which contains the pcie slot name.
108 pcie_slot_full_path.append("/label");
109 pcie_slot_name = readPropertyFile(pcie_slot_full_path);
110
111 if (pcie_slot_name.empty())
112 {
113 continue;
114 }
115
116 // Get the i2c bus number from the i2c device path.
117 std::uint32_t i2c_bus_number =
118 i2c_dev_string_number[2].matched
119 ? std::stoi(i2c_dev_string_number[2])
120 : 0;
121 // Store the i2c bus number and the pcie slot name in the vector.
122 pcie_i2c_map.push_back(
123 std::make_tuple(i2c_bus_number, pcie_slot_name));
124 }
125 }
126
127 return pcie_i2c_map;
128}
129
Patrick Ventureab650002019-03-16 09:08:47 -0700130} // namespace ipmi
131} // namespace google