blob: 08571c118d69e6f765e7959c8e54dffb991ab1bd [file] [log] [blame]
Shawn McCarney71d7fe42024-05-02 16:06:10 -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 "ucd90x_device.hpp"
23
24#include <cstdint>
25#include <exception>
26#include <map>
27#include <memory>
28#include <optional>
29#include <string>
30#include <utility>
31#include <vector>
32
33#include <gmock/gmock.h>
34#include <gtest/gtest.h>
35
36using namespace phosphor::power::sequencer;
37using namespace phosphor::pmbus;
38
39using ::testing::Return;
40using ::testing::Throw;
41
42/**
43 * Creates a Rail object that checks for a pgood fault using a GPIO.
44 *
45 * @param name Unique name for the rail
46 * @param gpio GPIO line to read to determine the pgood status of the rail
47 * @return Rail object
48 */
Shawn McCarneyfec38332024-05-02 13:58:56 -050049static std::unique_ptr<Rail> createRail(const std::string& name,
50 unsigned int gpioLine)
Shawn McCarney71d7fe42024-05-02 16:06:10 -050051{
52 std::optional<std::string> presence{};
53 std::optional<uint8_t> page{};
54 bool isPowerSupplyRail{false};
55 bool checkStatusVout{false};
56 bool compareVoltageToLimit{false};
57 bool activeLow{false};
Shawn McCarney984be692025-11-18 16:38:29 -060058 std::optional<PgoodGPIO> gpio{PgoodGPIO{gpioLine, activeLow}};
Shawn McCarney71d7fe42024-05-02 16:06:10 -050059 return std::make_unique<Rail>(name, presence, page, isPowerSupplyRail,
60 checkStatusVout, compareVoltageToLimit, gpio);
61}
62
63TEST(UCD90xDeviceTests, Constructor)
64{
65 MockServices services;
66
67 std::string name{"ucd90320"};
Shawn McCarney31234452025-10-28 12:32:05 -050068 uint8_t bus{3};
69 uint16_t address{0x72};
Shawn McCarneyfe536672025-10-29 12:44:08 -050070 std::string powerControlGPIOName{"power-chassis-control"};
71 std::string powerGoodGPIOName{"power-chassis-good"};
Shawn McCarney71d7fe42024-05-02 16:06:10 -050072 std::vector<std::unique_ptr<Rail>> rails;
73 rails.emplace_back(createRail("VDD", 5));
74 rails.emplace_back(createRail("VIO", 7));
Shawn McCarneyfe536672025-10-29 12:44:08 -050075 UCD90xDevice device{name,
76 bus,
77 address,
78 powerControlGPIOName,
79 powerGoodGPIOName,
80 std::move(rails),
81 services};
Shawn McCarney71d7fe42024-05-02 16:06:10 -050082
83 EXPECT_EQ(device.getName(), name);
Shawn McCarney31234452025-10-28 12:32:05 -050084 EXPECT_EQ(device.getBus(), bus);
85 EXPECT_EQ(device.getAddress(), address);
Shawn McCarneyfe536672025-10-29 12:44:08 -050086 EXPECT_EQ(device.getPowerControlGPIOName(), powerControlGPIOName);
87 EXPECT_EQ(device.getPowerGoodGPIOName(), powerGoodGPIOName);
Shawn McCarney71d7fe42024-05-02 16:06:10 -050088 EXPECT_EQ(device.getRails().size(), 2);
89 EXPECT_EQ(device.getRails()[0]->getName(), "VDD");
90 EXPECT_EQ(device.getRails()[1]->getName(), "VIO");
Shawn McCarney71d7fe42024-05-02 16:06:10 -050091 EXPECT_EQ(device.getDriverName(), "ucd9000");
92 EXPECT_EQ(device.getInstance(), 0);
93 EXPECT_NE(&(device.getPMBusInterface()), nullptr);
94}
95
96TEST(UCD90xDeviceTests, GetMfrStatus)
97{
98 // Test where works
99 {
100 MockServices services;
101
102 std::string name{"ucd90320"};
Shawn McCarney71d7fe42024-05-02 16:06:10 -0500103 uint8_t bus{3};
104 uint16_t address{0x72};
Shawn McCarneyfe536672025-10-29 12:44:08 -0500105 std::string powerControlGPIOName{"power-chassis-control"};
106 std::string powerGoodGPIOName{"power-chassis-good"};
Shawn McCarney31234452025-10-28 12:32:05 -0500107 std::vector<std::unique_ptr<Rail>> rails;
Shawn McCarneyfe536672025-10-29 12:44:08 -0500108 UCD90xDevice device{name,
109 bus,
110 address,
111 powerControlGPIOName,
112 powerGoodGPIOName,
113 std::move(rails),
114 services};
Shawn McCarney71d7fe42024-05-02 16:06:10 -0500115
116 MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface());
117 uint64_t mfrStatus{0x123456789abcull};
118 EXPECT_CALL(pmbus, read("mfr_status", Type::HwmonDeviceDebug, true))
119 .Times(1)
120 .WillOnce(Return(mfrStatus));
121
122 EXPECT_EQ(device.getMfrStatus(), mfrStatus);
123 }
124
125 // Test where fails with exception
126 {
127 MockServices services;
128
129 std::string name{"ucd90320"};
Shawn McCarney71d7fe42024-05-02 16:06:10 -0500130 uint8_t bus{3};
131 uint16_t address{0x72};
Shawn McCarneyfe536672025-10-29 12:44:08 -0500132 std::string powerControlGPIOName{"power-chassis-control"};
133 std::string powerGoodGPIOName{"power-chassis-good"};
Shawn McCarney31234452025-10-28 12:32:05 -0500134 std::vector<std::unique_ptr<Rail>> rails;
Shawn McCarneyfe536672025-10-29 12:44:08 -0500135 UCD90xDevice device{name,
136 bus,
137 address,
138 powerControlGPIOName,
139 powerGoodGPIOName,
140 std::move(rails),
141 services};
Shawn McCarney71d7fe42024-05-02 16:06:10 -0500142
143 MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface());
144 EXPECT_CALL(pmbus, read("mfr_status", Type::HwmonDeviceDebug, true))
145 .Times(1)
146 .WillOnce(Throw(std::runtime_error{"File does not exist"}));
147
148 try
149 {
150 device.getMfrStatus();
151 ADD_FAILURE() << "Should not have reached this line.";
152 }
153 catch (const std::exception& e)
154 {
155 EXPECT_STREQ(e.what(),
156 "Unable to read MFR_STATUS for device ucd90320: "
157 "File does not exist");
158 }
159 }
160}
161
162TEST(UCD90xDeviceTests, StorePgoodFaultDebugData)
163{
164 // This is a protected method and cannot be called directly from a gtest.
165 // Call findPgoodFault() which calls storePgoodFaultDebugData().
166
167 // Test where works
168 {
169 MockServices services;
170 std::vector<int> gpioValues{1, 1, 0};
171 EXPECT_CALL(services, getGPIOValues("ucd90320"))
172 .Times(1)
173 .WillOnce(Return(gpioValues));
174 EXPECT_CALL(services,
175 logInfoMsg("Device ucd90320 GPIO values: [1, 1, 0]"))
176 .Times(1);
177 EXPECT_CALL(services,
178 logInfoMsg("Device ucd90320 MFR_STATUS: 0x123456789abc"))
179 .Times(1);
180 EXPECT_CALL(
181 services,
182 logErrorMsg(
183 "Pgood fault found in rail monitored by device ucd90320"))
184 .Times(1);
185 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD"))
186 .Times(1);
187 EXPECT_CALL(
188 services,
189 logErrorMsg(
190 "Rail VDD pgood GPIO line offset 2 has inactive value 0"))
191 .Times(1);
192
193 std::string name{"ucd90320"};
Shawn McCarney71d7fe42024-05-02 16:06:10 -0500194 uint8_t bus{3};
195 uint16_t address{0x72};
Shawn McCarneyfe536672025-10-29 12:44:08 -0500196 std::string powerControlGPIOName{"power-chassis-control"};
197 std::string powerGoodGPIOName{"power-chassis-good"};
Shawn McCarney31234452025-10-28 12:32:05 -0500198 std::vector<std::unique_ptr<Rail>> rails;
199 rails.emplace_back(createRail("VDD", 2));
Shawn McCarneyfe536672025-10-29 12:44:08 -0500200 UCD90xDevice device{name,
201 bus,
202 address,
203 powerControlGPIOName,
204 powerGoodGPIOName,
205 std::move(rails),
206 services};
Shawn McCarney71d7fe42024-05-02 16:06:10 -0500207
208 MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface());
209 EXPECT_CALL(pmbus, getPath(Type::Hwmon))
210 .Times(1)
211 .WillOnce(Return("/tmp"));
212 EXPECT_CALL(pmbus, read("mfr_status", Type::HwmonDeviceDebug, true))
213 .Times(1)
214 .WillOnce(Return(0x123456789abcull));
215
216 // Call findPgoodFault() which calls storePgoodFaultDebugData()
217 std::string powerSupplyError{};
218 std::map<std::string, std::string> additionalData{};
Patrick Williamsf5402192024-08-16 15:20:53 -0400219 std::string error =
220 device.findPgoodFault(services, powerSupplyError, additionalData);
Shawn McCarney71d7fe42024-05-02 16:06:10 -0500221 EXPECT_EQ(error,
222 "xyz.openbmc_project.Power.Error.PowerSequencerVoltageFault");
223 EXPECT_EQ(additionalData.size(), 6);
224 EXPECT_EQ(additionalData["MFR_STATUS"], "0x123456789abc");
225 EXPECT_EQ(additionalData["DEVICE_NAME"], "ucd90320");
226 EXPECT_EQ(additionalData["GPIO_VALUES"], "[1, 1, 0]");
227 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD");
228 EXPECT_EQ(additionalData["GPIO_LINE"], "2");
229 EXPECT_EQ(additionalData["GPIO_VALUE"], "0");
230 }
231
232 // Test where exception thrown trying to get MFR_STATUS
233 {
234 MockServices services;
235 std::vector<int> gpioValues{1, 1, 0};
236 EXPECT_CALL(services, getGPIOValues("ucd90320"))
237 .Times(1)
238 .WillOnce(Return(gpioValues));
239 EXPECT_CALL(services,
240 logInfoMsg("Device ucd90320 GPIO values: [1, 1, 0]"))
241 .Times(1);
242 EXPECT_CALL(
243 services,
244 logErrorMsg(
245 "Pgood fault found in rail monitored by device ucd90320"))
246 .Times(1);
247 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD"))
248 .Times(1);
249 EXPECT_CALL(
250 services,
251 logErrorMsg(
252 "Rail VDD pgood GPIO line offset 2 has inactive value 0"))
253 .Times(1);
254
255 std::string name{"ucd90320"};
Shawn McCarney71d7fe42024-05-02 16:06:10 -0500256 uint8_t bus{3};
257 uint16_t address{0x72};
Shawn McCarneyfe536672025-10-29 12:44:08 -0500258 std::string powerControlGPIOName{"power-chassis-control"};
259 std::string powerGoodGPIOName{"power-chassis-good"};
Shawn McCarney31234452025-10-28 12:32:05 -0500260 std::vector<std::unique_ptr<Rail>> rails;
261 rails.emplace_back(createRail("VDD", 2));
Shawn McCarneyfe536672025-10-29 12:44:08 -0500262 UCD90xDevice device{name,
263 bus,
264 address,
265 powerControlGPIOName,
266 powerGoodGPIOName,
267 std::move(rails),
268 services};
Shawn McCarney71d7fe42024-05-02 16:06:10 -0500269
270 MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface());
271 EXPECT_CALL(pmbus, getPath(Type::Hwmon))
272 .Times(1)
273 .WillOnce(Return("/tmp"));
274 EXPECT_CALL(pmbus, read("mfr_status", Type::HwmonDeviceDebug, true))
275 .Times(1)
276 .WillOnce(Throw(std::runtime_error{"File does not exist"}));
277
278 // Call findPgoodFault() which calls storePgoodFaultDebugData()
279 std::string powerSupplyError{};
280 std::map<std::string, std::string> additionalData{};
Patrick Williamsf5402192024-08-16 15:20:53 -0400281 std::string error =
282 device.findPgoodFault(services, powerSupplyError, additionalData);
Shawn McCarney71d7fe42024-05-02 16:06:10 -0500283 EXPECT_EQ(error,
284 "xyz.openbmc_project.Power.Error.PowerSequencerVoltageFault");
285 EXPECT_EQ(additionalData.size(), 5);
286 EXPECT_EQ(additionalData["DEVICE_NAME"], "ucd90320");
287 EXPECT_EQ(additionalData["GPIO_VALUES"], "[1, 1, 0]");
288 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD");
289 EXPECT_EQ(additionalData["GPIO_LINE"], "2");
290 EXPECT_EQ(additionalData["GPIO_VALUE"], "0");
291 }
292}