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