blob: cf4c90c9a5fb453846e60d377d8a14452203100e [file] [log] [blame]
Shawn McCarney472101c2024-04-17 16:31:09 -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_services.hpp"
18#include "rail.hpp"
Shawn McCarneyfc3f31f2024-04-23 17:02:44 -050019#include "services.hpp"
Shawn McCarney472101c2024-04-17 16:31:09 -050020#include "standard_device.hpp"
21
22#include <cstdint>
23#include <map>
24#include <memory>
25#include <optional>
26#include <string>
27#include <utility>
28#include <vector>
29
30#include <gmock/gmock.h>
31#include <gtest/gtest.h>
32
33using namespace phosphor::power::sequencer;
34
35using ::testing::Return;
36using ::testing::Throw;
37
38/**
39 * @class StandardDeviceImpl
40 *
41 * Concrete subclass of the StandardDevice abstract class.
42 *
43 * This subclass is required for two reasons:
44 * - StandardDevice has some pure virtual methods so it cannot be instantiated.
45 * - The pure virtual methods provide the PMBus and GPIO information. Mocking
46 * these makes it possible to test the pgood fault detection algorithm.
47 *
48 * This class is not intended to be used outside of this file. It is
49 * implementation detail for testing the the StandardDevice class.
50 */
51class StandardDeviceImpl : public StandardDevice
52{
53 public:
54 // Specify which compiler-generated methods we want
55 StandardDeviceImpl() = delete;
56 StandardDeviceImpl(const StandardDeviceImpl&) = delete;
57 StandardDeviceImpl(StandardDeviceImpl&&) = delete;
58 StandardDeviceImpl& operator=(const StandardDeviceImpl&) = delete;
59 StandardDeviceImpl& operator=(StandardDeviceImpl&&) = delete;
60 virtual ~StandardDeviceImpl() = default;
61
62 // Constructor just calls StandardDevice constructor
Shawn McCarney31234452025-10-28 12:32:05 -050063 explicit StandardDeviceImpl(const std::string& name, uint8_t bus,
64 uint16_t address,
Shawn McCarney472101c2024-04-17 16:31:09 -050065 std::vector<std::unique_ptr<Rail>> rails) :
Shawn McCarney31234452025-10-28 12:32:05 -050066 StandardDevice(name, bus, address, std::move(rails))
Shawn McCarney472101c2024-04-17 16:31:09 -050067 {}
68
69 // Mock pure virtual methods
Shawn McCarneyfc3f31f2024-04-23 17:02:44 -050070 MOCK_METHOD(std::vector<int>, getGPIOValues, (Services & services),
71 (override));
Shawn McCarney472101c2024-04-17 16:31:09 -050072 MOCK_METHOD(uint16_t, getStatusWord, (uint8_t page), (override));
73 MOCK_METHOD(uint8_t, getStatusVout, (uint8_t page), (override));
74 MOCK_METHOD(double, getReadVout, (uint8_t page), (override));
75 MOCK_METHOD(double, getVoutUVFaultLimit, (uint8_t page), (override));
Shawn McCarney16275832024-06-27 10:14:11 -050076
77 // Override empty implementation with mock so we can verify it is called
78 MOCK_METHOD(void, prepareForPgoodFaultDetection, (Services & services),
79 (override));
Shawn McCarney472101c2024-04-17 16:31:09 -050080};
81
82/**
83 * Creates a Rail object that checks for a pgood fault using STATUS_VOUT.
84 *
85 * @param name Unique name for the rail
86 * @param isPowerSupplyRail Specifies whether the rail is produced by a
87 power supply
88 * @param pageNum PMBus PAGE number of the rail
89 * @return Rail object
90 */
Patrick Williamsf5402192024-08-16 15:20:53 -040091std::unique_ptr<Rail> createRailStatusVout(
92 const std::string& name, bool isPowerSupplyRail, uint8_t pageNum)
Shawn McCarney472101c2024-04-17 16:31:09 -050093{
94 std::optional<std::string> presence{};
95 std::optional<uint8_t> page{pageNum};
96 bool checkStatusVout{true};
97 bool compareVoltageToLimit{false};
98 std::optional<GPIO> gpio{};
99 return std::make_unique<Rail>(name, presence, page, isPowerSupplyRail,
100 checkStatusVout, compareVoltageToLimit, gpio);
101}
102
103/**
104 * Creates a Rail object that checks for a pgood fault using a GPIO.
105 *
106 * @param name Unique name for the rail
107 * @param isPowerSupplyRail Specifies whether the rail is produced by a
108 power supply
109 * @param gpio GPIO line to read to determine the pgood status of the rail
110 * @return Rail object
111 */
Patrick Williamsf5402192024-08-16 15:20:53 -0400112std::unique_ptr<Rail> createRailGPIO(
113 const std::string& name, bool isPowerSupplyRail, unsigned int gpioLine)
Shawn McCarney472101c2024-04-17 16:31:09 -0500114{
115 std::optional<std::string> presence{};
116 std::optional<uint8_t> page{};
117 bool checkStatusVout{false};
118 bool compareVoltageToLimit{false};
119 bool activeLow{false};
120 std::optional<GPIO> gpio{GPIO{gpioLine, activeLow}};
121 return std::make_unique<Rail>(name, presence, page, isPowerSupplyRail,
122 checkStatusVout, compareVoltageToLimit, gpio);
123}
124
Shawn McCarney16275832024-06-27 10:14:11 -0500125/**
126 * Creates a Rail object that checks for a pgood fault using output voltage.
127 *
128 * @param name Unique name for the rail
129 * @param isPowerSupplyRail Specifies whether the rail is produced by a
130 power supply
131 * @param pageNum PMBus PAGE number of the rail
132 * @return Rail object
133 */
Patrick Williamsf5402192024-08-16 15:20:53 -0400134std::unique_ptr<Rail> createRailOutputVoltage(
135 const std::string& name, bool isPowerSupplyRail, uint8_t pageNum)
Shawn McCarney16275832024-06-27 10:14:11 -0500136{
137 std::optional<std::string> presence{};
138 std::optional<uint8_t> page{pageNum};
139 bool checkStatusVout{false};
140 bool compareVoltageToLimit{true};
141 std::optional<GPIO> gpio{};
142 return std::make_unique<Rail>(name, presence, page, isPowerSupplyRail,
143 checkStatusVout, compareVoltageToLimit, gpio);
144}
145
Shawn McCarney472101c2024-04-17 16:31:09 -0500146TEST(StandardDeviceTests, Constructor)
147{
148 // Empty vector of rails
149 {
Shawn McCarney31234452025-10-28 12:32:05 -0500150 std::string name{"xyz_pseq"};
151 uint8_t bus{3};
152 uint16_t address{0x72};
Shawn McCarney472101c2024-04-17 16:31:09 -0500153 std::vector<std::unique_ptr<Rail>> rails{};
Shawn McCarney31234452025-10-28 12:32:05 -0500154 StandardDeviceImpl device{name, bus, address, std::move(rails)};
Shawn McCarney472101c2024-04-17 16:31:09 -0500155
Shawn McCarney31234452025-10-28 12:32:05 -0500156 EXPECT_EQ(device.getName(), name);
157 EXPECT_EQ(device.getBus(), bus);
158 EXPECT_EQ(device.getAddress(), address);
Shawn McCarney472101c2024-04-17 16:31:09 -0500159 EXPECT_TRUE(device.getRails().empty());
160 }
161
162 // Non-empty vector of rails
163 {
Shawn McCarney31234452025-10-28 12:32:05 -0500164 std::string name{"abc_pseq"};
165 uint8_t bus{0};
166 uint16_t address{0x23};
Shawn McCarney472101c2024-04-17 16:31:09 -0500167 std::vector<std::unique_ptr<Rail>> rails{};
168 rails.emplace_back(createRailGPIO("PSU", true, 3));
Shawn McCarney16275832024-06-27 10:14:11 -0500169 rails.emplace_back(createRailOutputVoltage("VDD", false, 5));
Shawn McCarney472101c2024-04-17 16:31:09 -0500170 rails.emplace_back(createRailStatusVout("VIO", false, 7));
Shawn McCarney31234452025-10-28 12:32:05 -0500171 StandardDeviceImpl device{name, bus, address, std::move(rails)};
Shawn McCarney472101c2024-04-17 16:31:09 -0500172
Shawn McCarney31234452025-10-28 12:32:05 -0500173 EXPECT_EQ(device.getName(), name);
174 EXPECT_EQ(device.getBus(), bus);
175 EXPECT_EQ(device.getAddress(), address);
Shawn McCarney472101c2024-04-17 16:31:09 -0500176 EXPECT_EQ(device.getRails().size(), 3);
177 EXPECT_EQ(device.getRails()[0]->getName(), "PSU");
178 EXPECT_EQ(device.getRails()[1]->getName(), "VDD");
179 EXPECT_EQ(device.getRails()[2]->getName(), "VIO");
180 }
181}
182
183TEST(StandardDeviceTests, GetName)
184{
Shawn McCarney31234452025-10-28 12:32:05 -0500185 std::string name{"xyz_pseq"};
186 uint8_t bus{0};
187 uint16_t address{0x23};
Shawn McCarney472101c2024-04-17 16:31:09 -0500188 std::vector<std::unique_ptr<Rail>> rails{};
Shawn McCarney31234452025-10-28 12:32:05 -0500189 StandardDeviceImpl device{name, bus, address, std::move(rails)};
Shawn McCarney472101c2024-04-17 16:31:09 -0500190
Shawn McCarney31234452025-10-28 12:32:05 -0500191 EXPECT_EQ(device.getName(), name);
192}
193
194TEST(StandardDeviceTests, GetBus)
195{
196 std::string name{"abc_pseq"};
197 uint8_t bus{1};
198 uint16_t address{0x23};
199 std::vector<std::unique_ptr<Rail>> rails{};
200 StandardDeviceImpl device{name, bus, address, std::move(rails)};
201
202 EXPECT_EQ(device.getBus(), bus);
203}
204
205TEST(StandardDeviceTests, GetAddress)
206{
207 std::string name{"abc_pseq"};
208 uint8_t bus{1};
209 uint16_t address{0x24};
210 std::vector<std::unique_ptr<Rail>> rails{};
211 StandardDeviceImpl device{name, bus, address, std::move(rails)};
212
213 EXPECT_EQ(device.getAddress(), address);
Shawn McCarney472101c2024-04-17 16:31:09 -0500214}
215
216TEST(StandardDeviceTests, GetRails)
217{
218 // Empty vector of rails
219 {
Shawn McCarney31234452025-10-28 12:32:05 -0500220 std::string name{"xyz_pseq"};
221 uint8_t bus{0};
222 uint16_t address{0x23};
Shawn McCarney472101c2024-04-17 16:31:09 -0500223 std::vector<std::unique_ptr<Rail>> rails{};
Shawn McCarney31234452025-10-28 12:32:05 -0500224 StandardDeviceImpl device{name, bus, address, std::move(rails)};
Shawn McCarney472101c2024-04-17 16:31:09 -0500225
226 EXPECT_TRUE(device.getRails().empty());
227 }
228
229 // Non-empty vector of rails
230 {
Shawn McCarney31234452025-10-28 12:32:05 -0500231 std::string name{"abc_pseq"};
232 uint8_t bus{0};
233 uint16_t address{0x23};
Shawn McCarney472101c2024-04-17 16:31:09 -0500234 std::vector<std::unique_ptr<Rail>> rails{};
235 rails.emplace_back(createRailGPIO("PSU", true, 3));
Shawn McCarney16275832024-06-27 10:14:11 -0500236 rails.emplace_back(createRailOutputVoltage("VDD", false, 5));
Shawn McCarney472101c2024-04-17 16:31:09 -0500237 rails.emplace_back(createRailStatusVout("VIO", false, 7));
Shawn McCarney31234452025-10-28 12:32:05 -0500238 StandardDeviceImpl device{name, bus, address, std::move(rails)};
Shawn McCarney472101c2024-04-17 16:31:09 -0500239
240 EXPECT_EQ(device.getRails().size(), 3);
241 EXPECT_EQ(device.getRails()[0]->getName(), "PSU");
242 EXPECT_EQ(device.getRails()[1]->getName(), "VDD");
243 EXPECT_EQ(device.getRails()[2]->getName(), "VIO");
244 }
245}
246
247TEST(StandardDeviceTests, FindPgoodFault)
248{
249 // No rail has a pgood fault
250 {
Shawn McCarney31234452025-10-28 12:32:05 -0500251 std::string name{"abc_pseq"};
252 uint8_t bus{0};
253 uint16_t address{0x23};
Shawn McCarney472101c2024-04-17 16:31:09 -0500254 std::vector<std::unique_ptr<Rail>> rails{};
255 rails.emplace_back(createRailGPIO("PSU", true, 2));
Shawn McCarney16275832024-06-27 10:14:11 -0500256 rails.emplace_back(createRailOutputVoltage("VDD", false, 5));
Shawn McCarney472101c2024-04-17 16:31:09 -0500257 rails.emplace_back(createRailStatusVout("VIO", false, 7));
Shawn McCarney31234452025-10-28 12:32:05 -0500258 StandardDeviceImpl device{name, bus, address, std::move(rails)};
Shawn McCarney472101c2024-04-17 16:31:09 -0500259
Shawn McCarney16275832024-06-27 10:14:11 -0500260 EXPECT_CALL(device, prepareForPgoodFaultDetection).Times(1);
Shawn McCarney472101c2024-04-17 16:31:09 -0500261 std::vector<int> gpioValues{1, 1, 1};
262 EXPECT_CALL(device, getGPIOValues)
263 .Times(1)
264 .WillOnce(Return(gpioValues));
Shawn McCarney16275832024-06-27 10:14:11 -0500265 EXPECT_CALL(device, getReadVout(5)).Times(1).WillOnce(Return(1.2));
266 EXPECT_CALL(device, getVoutUVFaultLimit(5))
267 .Times(1)
268 .WillOnce(Return(1.1));
Shawn McCarney472101c2024-04-17 16:31:09 -0500269 EXPECT_CALL(device, getStatusVout(7)).Times(1).WillOnce(Return(0x00));
270
271 MockServices services{};
272
273 std::string powerSupplyError{};
274 std::map<std::string, std::string> additionalData{};
Patrick Williamsf5402192024-08-16 15:20:53 -0400275 std::string error =
276 device.findPgoodFault(services, powerSupplyError, additionalData);
Shawn McCarney472101c2024-04-17 16:31:09 -0500277 EXPECT_TRUE(error.empty());
278 EXPECT_EQ(additionalData.size(), 0);
279 }
280
Shawn McCarney16275832024-06-27 10:14:11 -0500281 // First rail has a pgood fault detected via GPIO
Shawn McCarney472101c2024-04-17 16:31:09 -0500282 // Is a PSU rail: No PSU error specified
283 {
Shawn McCarney31234452025-10-28 12:32:05 -0500284 std::string name{"abc_pseq"};
285 uint8_t bus{0};
286 uint16_t address{0x23};
Shawn McCarney472101c2024-04-17 16:31:09 -0500287 std::vector<std::unique_ptr<Rail>> rails{};
288 rails.emplace_back(createRailGPIO("PSU", true, 2));
Shawn McCarney16275832024-06-27 10:14:11 -0500289 rails.emplace_back(createRailOutputVoltage("VDD", false, 5));
Shawn McCarney472101c2024-04-17 16:31:09 -0500290 rails.emplace_back(createRailStatusVout("VIO", false, 7));
Shawn McCarney31234452025-10-28 12:32:05 -0500291 StandardDeviceImpl device{name, bus, address, std::move(rails)};
Shawn McCarney472101c2024-04-17 16:31:09 -0500292
Shawn McCarney16275832024-06-27 10:14:11 -0500293 EXPECT_CALL(device, prepareForPgoodFaultDetection).Times(1);
Shawn McCarney472101c2024-04-17 16:31:09 -0500294 std::vector<int> gpioValues{1, 1, 0};
295 EXPECT_CALL(device, getGPIOValues)
296 .Times(1)
297 .WillOnce(Return(gpioValues));
Shawn McCarney16275832024-06-27 10:14:11 -0500298 EXPECT_CALL(device, getReadVout(5)).Times(0);
299 EXPECT_CALL(device, getVoutUVFaultLimit(5)).Times(0);
300 EXPECT_CALL(device, getStatusVout(7)).Times(1).WillOnce(Return(0x00));
Shawn McCarney472101c2024-04-17 16:31:09 -0500301
302 MockServices services{};
303 EXPECT_CALL(services,
304 logInfoMsg("Device abc_pseq GPIO values: [1, 1, 0]"))
305 .Times(1);
306 EXPECT_CALL(
307 services,
308 logErrorMsg(
309 "Pgood fault found in rail monitored by device abc_pseq"))
310 .Times(1);
311 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail PSU"))
312 .Times(1);
313 EXPECT_CALL(
314 services,
315 logErrorMsg(
316 "Rail PSU pgood GPIO line offset 2 has inactive value 0"))
317 .Times(1);
318
319 std::string powerSupplyError{};
320 std::map<std::string, std::string> additionalData{};
Patrick Williamsf5402192024-08-16 15:20:53 -0400321 std::string error =
322 device.findPgoodFault(services, powerSupplyError, additionalData);
Shawn McCarney472101c2024-04-17 16:31:09 -0500323 EXPECT_EQ(error,
324 "xyz.openbmc_project.Power.Error.PowerSequencerVoltageFault");
325 EXPECT_EQ(additionalData.size(), 5);
326 EXPECT_EQ(additionalData["DEVICE_NAME"], "abc_pseq");
327 EXPECT_EQ(additionalData["GPIO_VALUES"], "[1, 1, 0]");
328 EXPECT_EQ(additionalData["RAIL_NAME"], "PSU");
329 EXPECT_EQ(additionalData["GPIO_LINE"], "2");
330 EXPECT_EQ(additionalData["GPIO_VALUE"], "0");
331 }
332
Shawn McCarney16275832024-06-27 10:14:11 -0500333 // First rail has a pgood fault detected via GPIO
Shawn McCarney472101c2024-04-17 16:31:09 -0500334 // Is a PSU rail: PSU error specified
335 {
Shawn McCarney31234452025-10-28 12:32:05 -0500336 std::string name{"abc_pseq"};
337 uint8_t bus{0};
338 uint16_t address{0x23};
Shawn McCarney472101c2024-04-17 16:31:09 -0500339 std::vector<std::unique_ptr<Rail>> rails{};
340 rails.emplace_back(createRailGPIO("PSU", true, 2));
Shawn McCarney16275832024-06-27 10:14:11 -0500341 rails.emplace_back(createRailOutputVoltage("VDD", false, 5));
Shawn McCarney472101c2024-04-17 16:31:09 -0500342 rails.emplace_back(createRailStatusVout("VIO", false, 7));
Shawn McCarney31234452025-10-28 12:32:05 -0500343 StandardDeviceImpl device{name, bus, address, std::move(rails)};
Shawn McCarney472101c2024-04-17 16:31:09 -0500344
Shawn McCarney16275832024-06-27 10:14:11 -0500345 EXPECT_CALL(device, prepareForPgoodFaultDetection).Times(1);
Shawn McCarney472101c2024-04-17 16:31:09 -0500346 std::vector<int> gpioValues{1, 1, 0};
347 EXPECT_CALL(device, getGPIOValues)
348 .Times(1)
349 .WillOnce(Return(gpioValues));
Shawn McCarney16275832024-06-27 10:14:11 -0500350 EXPECT_CALL(device, getReadVout(5)).Times(0);
351 EXPECT_CALL(device, getVoutUVFaultLimit(5)).Times(0);
352 EXPECT_CALL(device, getStatusVout(7)).Times(1).WillOnce(Return(0x00));
Shawn McCarney472101c2024-04-17 16:31:09 -0500353
354 MockServices services{};
355 EXPECT_CALL(services,
356 logInfoMsg("Device abc_pseq GPIO values: [1, 1, 0]"))
357 .Times(1);
358 EXPECT_CALL(
359 services,
360 logErrorMsg(
361 "Pgood fault found in rail monitored by device abc_pseq"))
362 .Times(1);
363 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail PSU"))
364 .Times(1);
365 EXPECT_CALL(
366 services,
367 logErrorMsg(
368 "Rail PSU pgood GPIO line offset 2 has inactive value 0"))
369 .Times(1);
370
371 std::string powerSupplyError{"Undervoltage fault: PSU1"};
372 std::map<std::string, std::string> additionalData{};
Patrick Williamsf5402192024-08-16 15:20:53 -0400373 std::string error =
374 device.findPgoodFault(services, powerSupplyError, additionalData);
Shawn McCarney472101c2024-04-17 16:31:09 -0500375 EXPECT_EQ(error, powerSupplyError);
376 EXPECT_EQ(additionalData.size(), 5);
377 EXPECT_EQ(additionalData["DEVICE_NAME"], "abc_pseq");
378 EXPECT_EQ(additionalData["GPIO_VALUES"], "[1, 1, 0]");
379 EXPECT_EQ(additionalData["RAIL_NAME"], "PSU");
380 EXPECT_EQ(additionalData["GPIO_LINE"], "2");
381 EXPECT_EQ(additionalData["GPIO_VALUE"], "0");
382 }
383
Shawn McCarney16275832024-06-27 10:14:11 -0500384 // Second rail has a pgood fault detected via output voltage
Shawn McCarney472101c2024-04-17 16:31:09 -0500385 // Not a PSU rail: PSU error specified
386 {
Shawn McCarney31234452025-10-28 12:32:05 -0500387 std::string name{"abc_pseq"};
388 uint8_t bus{0};
389 uint16_t address{0x23};
Shawn McCarney472101c2024-04-17 16:31:09 -0500390 std::vector<std::unique_ptr<Rail>> rails{};
391 rails.emplace_back(createRailGPIO("PSU", true, 2));
Shawn McCarney16275832024-06-27 10:14:11 -0500392 rails.emplace_back(createRailOutputVoltage("VDD", false, 5));
Shawn McCarney472101c2024-04-17 16:31:09 -0500393 rails.emplace_back(createRailStatusVout("VIO", false, 7));
Shawn McCarney31234452025-10-28 12:32:05 -0500394 StandardDeviceImpl device{name, bus, address, std::move(rails)};
Shawn McCarney472101c2024-04-17 16:31:09 -0500395
Shawn McCarney16275832024-06-27 10:14:11 -0500396 EXPECT_CALL(device, prepareForPgoodFaultDetection).Times(1);
Shawn McCarney472101c2024-04-17 16:31:09 -0500397 std::vector<int> gpioValues{1, 1, 1};
398 EXPECT_CALL(device, getGPIOValues)
399 .Times(1)
400 .WillOnce(Return(gpioValues));
Shawn McCarney16275832024-06-27 10:14:11 -0500401 EXPECT_CALL(device, getReadVout(5)).Times(1).WillOnce(Return(1.1));
402 EXPECT_CALL(device, getVoutUVFaultLimit(5))
403 .Times(1)
404 .WillOnce(Return(1.2));
405 EXPECT_CALL(device, getStatusVout(7)).Times(1).WillOnce(Return(0x00));
Shawn McCarney472101c2024-04-17 16:31:09 -0500406 EXPECT_CALL(device, getStatusWord(5)).Times(1).WillOnce(Return(0xbeef));
407
408 MockServices services{};
409 EXPECT_CALL(services,
410 logInfoMsg("Device abc_pseq GPIO values: [1, 1, 1]"))
411 .Times(1);
412 EXPECT_CALL(
413 services,
414 logErrorMsg(
415 "Pgood fault found in rail monitored by device abc_pseq"))
416 .Times(1);
417 EXPECT_CALL(services, logInfoMsg("Rail VDD STATUS_WORD: 0xbeef"))
418 .Times(1);
419 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD"))
420 .Times(1);
421 EXPECT_CALL(
422 services,
Shawn McCarney16275832024-06-27 10:14:11 -0500423 logErrorMsg(
424 "Rail VDD output voltage 1.1V is <= UV fault limit 1.2V"))
Shawn McCarney472101c2024-04-17 16:31:09 -0500425 .Times(1);
426
427 std::string powerSupplyError{"Undervoltage fault: PSU1"};
428 std::map<std::string, std::string> additionalData{};
Patrick Williamsf5402192024-08-16 15:20:53 -0400429 std::string error =
430 device.findPgoodFault(services, powerSupplyError, additionalData);
Shawn McCarney472101c2024-04-17 16:31:09 -0500431 EXPECT_EQ(error,
432 "xyz.openbmc_project.Power.Error.PowerSequencerVoltageFault");
Shawn McCarney16275832024-06-27 10:14:11 -0500433 EXPECT_EQ(additionalData.size(), 6);
Shawn McCarney472101c2024-04-17 16:31:09 -0500434 EXPECT_EQ(additionalData["DEVICE_NAME"], "abc_pseq");
435 EXPECT_EQ(additionalData["GPIO_VALUES"], "[1, 1, 1]");
436 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD");
Shawn McCarney16275832024-06-27 10:14:11 -0500437 EXPECT_EQ(additionalData["READ_VOUT"], "1.1");
438 EXPECT_EQ(additionalData["VOUT_UV_FAULT_LIMIT"], "1.2");
Shawn McCarney472101c2024-04-17 16:31:09 -0500439 EXPECT_EQ(additionalData["STATUS_WORD"], "0xbeef");
440 }
441
Shawn McCarney16275832024-06-27 10:14:11 -0500442 // Third rail has a pgood fault detected via STATUS_VOUT
Shawn McCarney472101c2024-04-17 16:31:09 -0500443 // Device returns 0 GPIO values
444 // Does not halt pgood fault detection because GPIO values not used by rails
445 {
Shawn McCarney31234452025-10-28 12:32:05 -0500446 std::string name{"abc_pseq"};
447 uint8_t bus{0};
448 uint16_t address{0x23};
Shawn McCarney472101c2024-04-17 16:31:09 -0500449 std::vector<std::unique_ptr<Rail>> rails{};
450 rails.emplace_back(createRailStatusVout("PSU", true, 3));
Shawn McCarney16275832024-06-27 10:14:11 -0500451 rails.emplace_back(createRailOutputVoltage("VDD", false, 5));
Shawn McCarney472101c2024-04-17 16:31:09 -0500452 rails.emplace_back(createRailStatusVout("VIO", false, 7));
Shawn McCarney31234452025-10-28 12:32:05 -0500453 StandardDeviceImpl device{name, bus, address, std::move(rails)};
Shawn McCarney472101c2024-04-17 16:31:09 -0500454
Shawn McCarney16275832024-06-27 10:14:11 -0500455 EXPECT_CALL(device, prepareForPgoodFaultDetection).Times(1);
Shawn McCarney472101c2024-04-17 16:31:09 -0500456 std::vector<int> gpioValues{};
457 EXPECT_CALL(device, getGPIOValues)
458 .Times(1)
459 .WillOnce(Return(gpioValues));
460 EXPECT_CALL(device, getStatusVout(3)).Times(1).WillOnce(Return(0x00));
Shawn McCarney16275832024-06-27 10:14:11 -0500461 EXPECT_CALL(device, getReadVout(5)).Times(0);
462 EXPECT_CALL(device, getVoutUVFaultLimit(5)).Times(0);
Shawn McCarney472101c2024-04-17 16:31:09 -0500463 EXPECT_CALL(device, getStatusVout(7)).Times(1).WillOnce(Return(0x11));
464 EXPECT_CALL(device, getStatusWord(7)).Times(1).WillOnce(Return(0xbeef));
465
466 MockServices services{};
467 EXPECT_CALL(
468 services,
469 logErrorMsg(
470 "Pgood fault found in rail monitored by device abc_pseq"))
471 .Times(1);
472 EXPECT_CALL(services, logInfoMsg("Rail VIO STATUS_WORD: 0xbeef"))
473 .Times(1);
474 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VIO"))
475 .Times(1);
476 EXPECT_CALL(
477 services,
478 logErrorMsg("Rail VIO has fault bits set in STATUS_VOUT: 0x11"))
479 .Times(1);
480
481 std::string powerSupplyError{};
482 std::map<std::string, std::string> additionalData{};
Patrick Williamsf5402192024-08-16 15:20:53 -0400483 std::string error =
484 device.findPgoodFault(services, powerSupplyError, additionalData);
Shawn McCarney472101c2024-04-17 16:31:09 -0500485 EXPECT_EQ(error,
486 "xyz.openbmc_project.Power.Error.PowerSequencerVoltageFault");
487 EXPECT_EQ(additionalData.size(), 4);
488 EXPECT_EQ(additionalData["DEVICE_NAME"], "abc_pseq");
489 EXPECT_EQ(additionalData["RAIL_NAME"], "VIO");
490 EXPECT_EQ(additionalData["STATUS_VOUT"], "0x11");
491 EXPECT_EQ(additionalData["STATUS_WORD"], "0xbeef");
492 }
493
Shawn McCarney16275832024-06-27 10:14:11 -0500494 // Third rail has a pgood fault detected via STATUS_VOUT
Shawn McCarney472101c2024-04-17 16:31:09 -0500495 // Exception occurs trying to obtain GPIO values from device
496 // Does not halt pgood fault detection because GPIO values not used by rails
497 {
Shawn McCarney31234452025-10-28 12:32:05 -0500498 std::string name{"abc_pseq"};
499 uint8_t bus{0};
500 uint16_t address{0x23};
Shawn McCarney472101c2024-04-17 16:31:09 -0500501 std::vector<std::unique_ptr<Rail>> rails{};
502 rails.emplace_back(createRailStatusVout("PSU", true, 3));
Shawn McCarney16275832024-06-27 10:14:11 -0500503 rails.emplace_back(createRailOutputVoltage("VDD", false, 5));
Shawn McCarney472101c2024-04-17 16:31:09 -0500504 rails.emplace_back(createRailStatusVout("VIO", false, 7));
Shawn McCarney31234452025-10-28 12:32:05 -0500505 StandardDeviceImpl device{name, bus, address, std::move(rails)};
Shawn McCarney472101c2024-04-17 16:31:09 -0500506
Shawn McCarney16275832024-06-27 10:14:11 -0500507 EXPECT_CALL(device, prepareForPgoodFaultDetection).Times(1);
Shawn McCarney472101c2024-04-17 16:31:09 -0500508 EXPECT_CALL(device, getGPIOValues)
509 .Times(1)
510 .WillOnce(Throw(std::runtime_error{"Unable to acquire GPIO line"}));
511 EXPECT_CALL(device, getStatusVout(3)).Times(1).WillOnce(Return(0x00));
Shawn McCarney16275832024-06-27 10:14:11 -0500512 EXPECT_CALL(device, getReadVout(5)).Times(0);
513 EXPECT_CALL(device, getVoutUVFaultLimit(5)).Times(0);
Shawn McCarney472101c2024-04-17 16:31:09 -0500514 EXPECT_CALL(device, getStatusVout(7)).Times(1).WillOnce(Return(0x11));
515 EXPECT_CALL(device, getStatusWord(7)).Times(1).WillOnce(Return(0xbeef));
516
517 MockServices services{};
518 EXPECT_CALL(
519 services,
520 logErrorMsg(
521 "Pgood fault found in rail monitored by device abc_pseq"))
522 .Times(1);
523 EXPECT_CALL(services, logInfoMsg("Rail VIO STATUS_WORD: 0xbeef"))
524 .Times(1);
525 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VIO"))
526 .Times(1);
527 EXPECT_CALL(
528 services,
529 logErrorMsg("Rail VIO has fault bits set in STATUS_VOUT: 0x11"))
530 .Times(1);
531
532 std::string powerSupplyError{};
533 std::map<std::string, std::string> additionalData{};
Patrick Williamsf5402192024-08-16 15:20:53 -0400534 std::string error =
535 device.findPgoodFault(services, powerSupplyError, additionalData);
Shawn McCarney472101c2024-04-17 16:31:09 -0500536 EXPECT_EQ(error,
537 "xyz.openbmc_project.Power.Error.PowerSequencerVoltageFault");
538 EXPECT_EQ(additionalData.size(), 4);
539 EXPECT_EQ(additionalData["DEVICE_NAME"], "abc_pseq");
540 EXPECT_EQ(additionalData["RAIL_NAME"], "VIO");
541 EXPECT_EQ(additionalData["STATUS_VOUT"], "0x11");
542 EXPECT_EQ(additionalData["STATUS_WORD"], "0xbeef");
543 }
544
Shawn McCarney16275832024-06-27 10:14:11 -0500545 // All three rails appear to have a pgood fault. Verify third rail is
546 // selected, even though it is last in the power on sequence, because it is
547 // checked using STATUS_VOUT. That check happens before the other checks.
548 {
Shawn McCarney31234452025-10-28 12:32:05 -0500549 std::string name{"abc_pseq"};
550 uint8_t bus{0};
551 uint16_t address{0x23};
Shawn McCarney16275832024-06-27 10:14:11 -0500552 std::vector<std::unique_ptr<Rail>> rails{};
553 rails.emplace_back(createRailGPIO("PSU", true, 2));
554 rails.emplace_back(createRailGPIO("VDD", false, 1));
555 rails.emplace_back(createRailStatusVout("VIO", false, 7));
Shawn McCarney31234452025-10-28 12:32:05 -0500556 StandardDeviceImpl device{name, bus, address, std::move(rails)};
Shawn McCarney16275832024-06-27 10:14:11 -0500557
558 EXPECT_CALL(device, prepareForPgoodFaultDetection).Times(1);
559 std::vector<int> gpioValues{0, 0, 0};
560 EXPECT_CALL(device, getGPIOValues)
561 .Times(1)
562 .WillOnce(Return(gpioValues));
563 EXPECT_CALL(device, getStatusVout(7)).Times(1).WillOnce(Return(0x11));
564 EXPECT_CALL(device, getStatusWord(7)).Times(1).WillOnce(Return(0xbeef));
565
566 MockServices services{};
567 EXPECT_CALL(services,
568 logInfoMsg("Device abc_pseq GPIO values: [0, 0, 0]"))
569 .Times(1);
570 EXPECT_CALL(
571 services,
572 logErrorMsg(
573 "Pgood fault found in rail monitored by device abc_pseq"))
574 .Times(1);
575 EXPECT_CALL(services, logInfoMsg("Rail VIO STATUS_WORD: 0xbeef"))
576 .Times(1);
577 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VIO"))
578 .Times(1);
579 EXPECT_CALL(
580 services,
581 logErrorMsg("Rail VIO has fault bits set in STATUS_VOUT: 0x11"))
582 .Times(1);
583
584 std::string powerSupplyError{};
585 std::map<std::string, std::string> additionalData{};
Patrick Williamsf5402192024-08-16 15:20:53 -0400586 std::string error =
587 device.findPgoodFault(services, powerSupplyError, additionalData);
Shawn McCarney16275832024-06-27 10:14:11 -0500588 EXPECT_EQ(error,
589 "xyz.openbmc_project.Power.Error.PowerSequencerVoltageFault");
590 EXPECT_EQ(additionalData.size(), 5);
591 EXPECT_EQ(additionalData["DEVICE_NAME"], "abc_pseq");
592 EXPECT_EQ(additionalData["GPIO_VALUES"], "[0, 0, 0]");
593 EXPECT_EQ(additionalData["RAIL_NAME"], "VIO");
594 EXPECT_EQ(additionalData["STATUS_VOUT"], "0x11");
595 EXPECT_EQ(additionalData["STATUS_WORD"], "0xbeef");
596 }
597
598 // Two rails appear to have a pgood fault. One is found via output voltage
599 // and one is found via a GPIO. Verify the first rail in the sequence with
600 // a fault is selected.
601 {
Shawn McCarney31234452025-10-28 12:32:05 -0500602 std::string name{"abc_pseq"};
603 uint8_t bus{0};
604 uint16_t address{0x23};
Shawn McCarney16275832024-06-27 10:14:11 -0500605 std::vector<std::unique_ptr<Rail>> rails{};
606 rails.emplace_back(createRailStatusVout("VIO", false, 7));
607 rails.emplace_back(createRailOutputVoltage("VDD", false, 5));
608 rails.emplace_back(createRailGPIO("PSU", true, 2));
Shawn McCarney31234452025-10-28 12:32:05 -0500609 StandardDeviceImpl device{name, bus, address, std::move(rails)};
Shawn McCarney16275832024-06-27 10:14:11 -0500610
611 EXPECT_CALL(device, prepareForPgoodFaultDetection).Times(1);
612 std::vector<int> gpioValues{1, 1, 0};
613 EXPECT_CALL(device, getGPIOValues)
614 .Times(1)
615 .WillOnce(Return(gpioValues));
616 EXPECT_CALL(device, getStatusVout(7)).Times(1).WillOnce(Return(0x00));
617 EXPECT_CALL(device, getReadVout(5)).Times(1).WillOnce(Return(1.1));
618 EXPECT_CALL(device, getVoutUVFaultLimit(5))
619 .Times(1)
620 .WillOnce(Return(1.2));
621 EXPECT_CALL(device, getStatusWord(5)).Times(1).WillOnce(Return(0xbeef));
622
623 MockServices services{};
624 EXPECT_CALL(services,
625 logInfoMsg("Device abc_pseq GPIO values: [1, 1, 0]"))
626 .Times(1);
627 EXPECT_CALL(
628 services,
629 logErrorMsg(
630 "Pgood fault found in rail monitored by device abc_pseq"))
631 .Times(1);
632 EXPECT_CALL(services, logInfoMsg("Rail VDD STATUS_WORD: 0xbeef"))
633 .Times(1);
634 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD"))
635 .Times(1);
636 EXPECT_CALL(
637 services,
638 logErrorMsg(
639 "Rail VDD output voltage 1.1V is <= UV fault limit 1.2V"))
640 .Times(1);
641
642 std::string powerSupplyError{};
643 std::map<std::string, std::string> additionalData{};
Patrick Williamsf5402192024-08-16 15:20:53 -0400644 std::string error =
645 device.findPgoodFault(services, powerSupplyError, additionalData);
Shawn McCarney16275832024-06-27 10:14:11 -0500646 EXPECT_EQ(error,
647 "xyz.openbmc_project.Power.Error.PowerSequencerVoltageFault");
648 EXPECT_EQ(additionalData.size(), 6);
649 EXPECT_EQ(additionalData["DEVICE_NAME"], "abc_pseq");
650 EXPECT_EQ(additionalData["GPIO_VALUES"], "[1, 1, 0]");
651 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD");
652 EXPECT_EQ(additionalData["READ_VOUT"], "1.1");
653 EXPECT_EQ(additionalData["VOUT_UV_FAULT_LIMIT"], "1.2");
654 EXPECT_EQ(additionalData["STATUS_WORD"], "0xbeef");
655 }
656
Shawn McCarney472101c2024-04-17 16:31:09 -0500657 // Exception is thrown during pgood fault detection
658 {
Shawn McCarney31234452025-10-28 12:32:05 -0500659 std::string name{"abc_pseq"};
660 uint8_t bus{0};
661 uint16_t address{0x23};
Shawn McCarney472101c2024-04-17 16:31:09 -0500662 std::vector<std::unique_ptr<Rail>> rails{};
663 rails.emplace_back(createRailGPIO("PSU", true, 2));
Shawn McCarney16275832024-06-27 10:14:11 -0500664 rails.emplace_back(createRailOutputVoltage("VDD", false, 5));
Shawn McCarney472101c2024-04-17 16:31:09 -0500665 rails.emplace_back(createRailStatusVout("VIO", false, 7));
Shawn McCarney31234452025-10-28 12:32:05 -0500666 StandardDeviceImpl device{name, bus, address, std::move(rails)};
Shawn McCarney472101c2024-04-17 16:31:09 -0500667
Shawn McCarney16275832024-06-27 10:14:11 -0500668 EXPECT_CALL(device, prepareForPgoodFaultDetection).Times(1);
Shawn McCarney472101c2024-04-17 16:31:09 -0500669 std::vector<int> gpioValues{1, 1, 1};
670 EXPECT_CALL(device, getGPIOValues)
671 .Times(1)
672 .WillOnce(Return(gpioValues));
Shawn McCarney16275832024-06-27 10:14:11 -0500673 EXPECT_CALL(device, getReadVout(5)).Times(0);
674 EXPECT_CALL(device, getVoutUVFaultLimit(5)).Times(0);
675 EXPECT_CALL(device, getStatusVout(7))
Shawn McCarney472101c2024-04-17 16:31:09 -0500676 .Times(1)
677 .WillOnce(Throw(std::runtime_error{"File does not exist"}));
Shawn McCarney472101c2024-04-17 16:31:09 -0500678
679 MockServices services{};
680
681 std::string powerSupplyError{};
682 std::map<std::string, std::string> additionalData{};
683 try
684 {
685 device.findPgoodFault(services, powerSupplyError, additionalData);
686 ADD_FAILURE() << "Should not have reached this line.";
687 }
688 catch (const std::exception& e)
689 {
690 EXPECT_STREQ(
691 e.what(),
692 "Unable to determine if a pgood fault occurred in device abc_pseq: "
Shawn McCarney16275832024-06-27 10:14:11 -0500693 "Unable to read STATUS_VOUT value for rail VIO: "
Shawn McCarney472101c2024-04-17 16:31:09 -0500694 "File does not exist");
695 }
696 }
697}