blob: 980b9608ca5d6e1ecd1677baeaa02e77d850cd09 [file] [log] [blame]
Shawn McCarneyfec38332024-05-02 13:58:56 -05001/**
2 * Copyright © 2024 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "mock_pmbus.hpp"
18#include "mock_services.hpp"
19#include "pmbus.hpp"
20#include "rail.hpp"
21#include "services.hpp"
22#include "ucd90320_device.hpp"
23
24#include <cstdint>
25#include <map>
26#include <memory>
27#include <optional>
28#include <string>
29#include <utility>
30#include <vector>
31
32#include <gmock/gmock.h>
33#include <gtest/gtest.h>
34
35using namespace phosphor::power::sequencer;
36using namespace phosphor::pmbus;
37
38using ::testing::Return;
39
40/**
41 * Creates a Rail object that checks for a pgood fault using a GPIO.
42 *
43 * @param name Unique name for the rail
44 * @param gpio GPIO line to read to determine the pgood status of the rail
45 * @return Rail object
46 */
47static std::unique_ptr<Rail> createRail(const std::string& name,
48 unsigned int gpioLine)
49{
50 std::optional<std::string> presence{};
51 std::optional<uint8_t> page{};
52 bool isPowerSupplyRail{false};
53 bool checkStatusVout{false};
54 bool compareVoltageToLimit{false};
55 bool activeLow{false};
56 std::optional<GPIO> gpio{GPIO{gpioLine, activeLow}};
57 return std::make_unique<Rail>(name, presence, page, isPowerSupplyRail,
58 checkStatusVout, compareVoltageToLimit, gpio);
59}
60
61TEST(UCD90320DeviceTests, Constructor)
62{
63 MockServices services;
64
65 std::vector<std::unique_ptr<Rail>> rails;
66 rails.emplace_back(createRail("VDD", 5));
67 rails.emplace_back(createRail("VIO", 7));
68 uint8_t bus{3};
69 uint16_t address{0x72};
70 UCD90320Device device{std::move(rails), services, bus, address};
71
72 EXPECT_EQ(device.getName(), "UCD90320");
73 EXPECT_EQ(device.getRails().size(), 2);
74 EXPECT_EQ(device.getRails()[0]->getName(), "VDD");
75 EXPECT_EQ(device.getRails()[1]->getName(), "VIO");
76 EXPECT_EQ(device.getBus(), bus);
77 EXPECT_EQ(device.getAddress(), address);
78 EXPECT_EQ(device.getDriverName(), "ucd9000");
79 EXPECT_EQ(device.getInstance(), 0);
80 EXPECT_NE(&(device.getPMBusInterface()), nullptr);
81}
82
83TEST(UCD90320DeviceTests, StoreGPIOValues)
84{
85 // This is a protected method and cannot be called directly from a gtest.
86 // Call findPgoodFault() which calls storeGPIOValues().
87
88 // Test where works
89 {
90 std::vector<int> gpioValues{
91 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, // MAR01-12
92 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, // MAR13-24
93 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, // EN1-12
94 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, // EN13-24
95 1, 1, 0, 0, 1, 1, 1, 0, // EN25-32
96 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, // LGP01-12
97 1, 1, 0, 0, // LGP13-16
98 1, 0, 0, 1, 1, 1, 0, 0, // DMON1-8
99 1, 0, 0, 1 // GPIO1-4
100 };
101
102 MockServices services;
103 EXPECT_CALL(services, getGPIOValues("ucd90320"))
104 .Times(1)
105 .WillOnce(Return(gpioValues));
106 EXPECT_CALL(services, logInfoMsg("Device UCD90320 GPIO values:"))
107 .Times(1);
108 EXPECT_CALL(services, logInfoMsg("MAR01-24: ["
109 "1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, "
110 "1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0]"))
111 .Times(1);
112 EXPECT_CALL(services, logInfoMsg("EN1-32: ["
113 "1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, "
114 "1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, "
115 "1, 1, 0, 0, 1, 1, 1, 0]"))
116 .Times(1);
117 EXPECT_CALL(services, logInfoMsg("LGP01-16: ["
118 "1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, "
119 "1, 1, 0, 0]"))
120 .Times(1);
121 EXPECT_CALL(services, logInfoMsg("DMON1-8: ["
122 "1, 0, 0, 1, 1, 1, 0, 0]"))
123 .Times(1);
124 EXPECT_CALL(services, logInfoMsg("GPIO1-4: ["
125 "1, 0, 0, 1]"))
126 .Times(1);
127 EXPECT_CALL(services,
128 logInfoMsg("Device UCD90320 MFR_STATUS: 0x123456789abc"))
129 .Times(1);
130 EXPECT_CALL(
131 services,
132 logErrorMsg(
133 "Pgood fault found in rail monitored by device UCD90320"))
134 .Times(1);
135 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD"))
136 .Times(1);
137 EXPECT_CALL(
138 services,
139 logErrorMsg(
140 "Rail VDD pgood GPIO line offset 2 has inactive value 0"))
141 .Times(1);
142
143 std::vector<std::unique_ptr<Rail>> rails;
144 rails.emplace_back(createRail("VDD", 2));
145 uint8_t bus{3};
146 uint16_t address{0x72};
147 UCD90320Device device{std::move(rails), services, bus, address};
148
149 MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface());
150 EXPECT_CALL(pmbus, getPath(Type::Hwmon))
151 .Times(1)
152 .WillOnce(Return("/tmp"));
153 EXPECT_CALL(pmbus, read("mfr_status", Type::HwmonDeviceDebug, true))
154 .Times(1)
155 .WillOnce(Return(0x123456789abcull));
156
157 // Call findPgoodFault() which calls storeGPIOValues()
158 std::string powerSupplyError{};
159 std::map<std::string, std::string> additionalData{};
160 std::string error = device.findPgoodFault(services, powerSupplyError,
161 additionalData);
162 EXPECT_EQ(error,
163 "xyz.openbmc_project.Power.Error.PowerSequencerVoltageFault");
164 EXPECT_EQ(additionalData.size(), 10);
165 EXPECT_EQ(additionalData["MFR_STATUS"], "0x123456789abc");
166 EXPECT_EQ(additionalData["DEVICE_NAME"], "UCD90320");
167 EXPECT_EQ(additionalData["MAR01_24_GPIO_VALUES"],
168 "[1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, "
169 "1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0]");
170 EXPECT_EQ(additionalData["EN1_32_GPIO_VALUES"],
171 "[1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, "
172 "1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, "
173 "1, 1, 0, 0, 1, 1, 1, 0]");
174 EXPECT_EQ(additionalData["LGP01_16_GPIO_VALUES"],
175 "[1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, "
176 "1, 1, 0, 0]");
177 EXPECT_EQ(additionalData["DMON1_8_GPIO_VALUES"],
178 "[1, 0, 0, 1, 1, 1, 0, 0]");
179 EXPECT_EQ(additionalData["GPIO1_4_GPIO_VALUES"], "[1, 0, 0, 1]");
180 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD");
181 EXPECT_EQ(additionalData["GPIO_LINE"], "2");
182 EXPECT_EQ(additionalData["GPIO_VALUE"], "0");
183 }
184
185 // Test where there are the wrong number of GPIOs (83 instead of 84)
186 {
187 std::vector<int> gpioValues{
188 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, // MAR01-12
189 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, // MAR13-24
190 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, // EN1-12
191 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, // EN13-24
192 1, 1, 0, 0, 1, 1, 1, 0, // EN25-32
193 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, // LGP01-12
194 1, 1, 0, 0, // LGP13-16
195 1, 0, 0, 1, 1, 1, 0, 0, // DMON1-8
196 1, 0, 0 // GPIO1-4 (1 missing)
197 };
198
199 MockServices services;
200 EXPECT_CALL(services, getGPIOValues("ucd90320"))
201 .Times(1)
202 .WillOnce(Return(gpioValues));
203 EXPECT_CALL(services, logInfoMsg("Device UCD90320 GPIO values: ["
204 "1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, "
205 "1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, "
206 "1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, "
207 "1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, "
208 "1, 1, 0, 0, 1, 1, 1, 0, "
209 "1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, "
210 "1, 1, 0, 0, "
211 "1, 0, 0, 1, 1, 1, 0, 0, "
212 "1, 0, 0]"))
213 .Times(1);
214 EXPECT_CALL(services,
215 logInfoMsg("Device UCD90320 MFR_STATUS: 0x123456789abc"))
216 .Times(1);
217 EXPECT_CALL(
218 services,
219 logErrorMsg(
220 "Pgood fault found in rail monitored by device UCD90320"))
221 .Times(1);
222 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD"))
223 .Times(1);
224 EXPECT_CALL(
225 services,
226 logErrorMsg(
227 "Rail VDD pgood GPIO line offset 2 has inactive value 0"))
228 .Times(1);
229
230 std::vector<std::unique_ptr<Rail>> rails;
231 rails.emplace_back(createRail("VDD", 2));
232 uint8_t bus{3};
233 uint16_t address{0x72};
234 UCD90320Device device{std::move(rails), services, bus, address};
235
236 MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface());
237 EXPECT_CALL(pmbus, getPath(Type::Hwmon))
238 .Times(1)
239 .WillOnce(Return("/tmp"));
240 EXPECT_CALL(pmbus, read("mfr_status", Type::HwmonDeviceDebug, true))
241 .Times(1)
242 .WillOnce(Return(0x123456789abcull));
243
244 // Call findPgoodFault() which calls storeGPIOValues()
245 std::string powerSupplyError{};
246 std::map<std::string, std::string> additionalData{};
247 std::string error = device.findPgoodFault(services, powerSupplyError,
248 additionalData);
249 EXPECT_EQ(error,
250 "xyz.openbmc_project.Power.Error.PowerSequencerVoltageFault");
251 EXPECT_EQ(additionalData.size(), 6);
252 EXPECT_EQ(additionalData["MFR_STATUS"], "0x123456789abc");
253 EXPECT_EQ(additionalData["DEVICE_NAME"], "UCD90320");
254 EXPECT_EQ(additionalData["GPIO_VALUES"],
255 "[1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, "
256 "1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, "
257 "1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, "
258 "1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, "
259 "1, 1, 0, 0, 1, 1, 1, 0, "
260 "1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, "
261 "1, 1, 0, 0, "
262 "1, 0, 0, 1, 1, 1, 0, 0, "
263 "1, 0, 0]");
264 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD");
265 EXPECT_EQ(additionalData["GPIO_LINE"], "2");
266 EXPECT_EQ(additionalData["GPIO_VALUE"], "0");
267 }
268}