1 // Copyright 2021 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "util.hpp"
16
17 #include <nlohmann/json.hpp>
18 #include <phosphor-logging/elog-errors.hpp>
19 #include <stdplus/print.hpp>
20 #include <xyz/openbmc_project/Common/error.hpp>
21
22 #include <cstdint>
23 #include <cstdio>
24 #include <filesystem>
25 #include <fstream>
26 #include <regex>
27 #include <string>
28 #include <tuple>
29 #include <vector>
30
31 namespace google
32 {
33 namespace ipmi
34 {
35 namespace fs = std::filesystem;
36 using namespace phosphor::logging;
37 using InternalFailure =
38 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
39
parseConfig(const std::string & file)40 nlohmann::json parseConfig(const std::string& file)
41 {
42 std::ifstream jsonFile(file);
43 if (!jsonFile.is_open())
44 {
45 log<level::ERR>("Entity association JSON file not found");
46 elog<InternalFailure>();
47 }
48
49 auto data = nlohmann::json::parse(jsonFile, nullptr, false);
50 if (data.is_discarded())
51 {
52 log<level::ERR>("Entity association JSON parser failure");
53 elog<InternalFailure>();
54 }
55
56 return data;
57 }
58
readPropertyFile(const std::string & fileName)59 std::string readPropertyFile(const std::string& fileName)
60 {
61 std::ifstream ifs(fileName);
62 std::string contents;
63
64 if (!ifs.is_open())
65 {
66 auto msg = std::string("Unable to open file ") + fileName.c_str();
67 log<level::DEBUG>(msg.c_str());
68 }
69 else
70 {
71 if (ifs >> contents)
72 {
73 // If the last character is a null terminator; remove it.
74 if (!contents.empty())
75 {
76 const char& back = contents.back();
77 if (back == '\0')
78 contents.pop_back();
79 }
80
81 return contents;
82 }
83 else
84 {
85 stdplus::print(stderr, "Unable to read file {}.\n", fileName);
86 }
87 }
88
89 return "";
90 }
91
buildPcieMap()92 std::vector<std::tuple<std::uint32_t, std::string>> buildPcieMap()
93 {
94 std::vector<std::tuple<std::uint32_t, std::string>> pcie_i2c_map;
95
96 // Build a vector with i2c bus to pcie slot mapping.
97 // Iterate through all the devices under "/sys/bus/i2c/devices".
98 for (const auto& i2c_dev : fs::directory_iterator("/sys/bus/i2c/devices"))
99 {
100 std::string i2c_dev_path = i2c_dev.path();
101 std::smatch i2c_dev_string_number;
102 std::regex e("(i2c-)(\\d+)");
103
104 // Check if the device has "i2c-" in its path.
105 if (std::regex_search(i2c_dev_path, i2c_dev_string_number, e))
106 {
107 // Check if the i2c device has "pcie-slot" file under "of-node" dir.
108 std::string pcie_slot_path = i2c_dev_path + "/of_node/pcie-slot";
109 std::string pcie_slot;
110
111 // Read the "pcie-slot" name from the "pcie-slot" file.
112 pcie_slot = readPropertyFile(pcie_slot_path);
113 if (pcie_slot.empty())
114 {
115 continue;
116 }
117 std::string pcie_slot_name;
118 std::string pcie_slot_full_path;
119
120 // Append the "pcie-slot" name to dts base.
121 pcie_slot_full_path.append("/proc/device-tree");
122 pcie_slot_full_path.append(pcie_slot);
123
124 // Read the "label" which contains the pcie slot name.
125 pcie_slot_full_path.append("/label");
126 pcie_slot_name = readPropertyFile(pcie_slot_full_path);
127
128 if (pcie_slot_name.empty())
129 {
130 continue;
131 }
132
133 // Get the i2c bus number from the i2c device path.
134 std::uint32_t i2c_bus_number =
135 i2c_dev_string_number[2].matched
136 ? std::stoi(i2c_dev_string_number[2])
137 : 0;
138 // Store the i2c bus number and the pcie slot name in the vector.
139 pcie_i2c_map.push_back(
140 std::make_tuple(i2c_bus_number, pcie_slot_name));
141 }
142 }
143
144 return pcie_i2c_map;
145 }
146
147 } // namespace ipmi
148 } // namespace google
149