1472101c5SShawn McCarney /**
2472101c5SShawn McCarney * Copyright © 2024 IBM Corporation
3472101c5SShawn McCarney *
4472101c5SShawn McCarney * Licensed under the Apache License, Version 2.0 (the "License");
5472101c5SShawn McCarney * you may not use this file except in compliance with the License.
6472101c5SShawn McCarney * You may obtain a copy of the License at
7472101c5SShawn McCarney *
8472101c5SShawn McCarney * http://www.apache.org/licenses/LICENSE-2.0
9472101c5SShawn McCarney *
10472101c5SShawn McCarney * Unless required by applicable law or agreed to in writing, software
11472101c5SShawn McCarney * distributed under the License is distributed on an "AS IS" BASIS,
12472101c5SShawn McCarney * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13472101c5SShawn McCarney * See the License for the specific language governing permissions and
14472101c5SShawn McCarney * limitations under the License.
15472101c5SShawn McCarney */
16472101c5SShawn McCarney
17472101c5SShawn McCarney #include "mock_services.hpp"
18472101c5SShawn McCarney #include "rail.hpp"
19fc3f31fbSShawn McCarney #include "services.hpp"
20472101c5SShawn McCarney #include "standard_device.hpp"
21472101c5SShawn McCarney
22472101c5SShawn McCarney #include <cstdint>
23472101c5SShawn McCarney #include <map>
24472101c5SShawn McCarney #include <memory>
25472101c5SShawn McCarney #include <optional>
26472101c5SShawn McCarney #include <string>
27472101c5SShawn McCarney #include <utility>
28472101c5SShawn McCarney #include <vector>
29472101c5SShawn McCarney
30472101c5SShawn McCarney #include <gmock/gmock.h>
31472101c5SShawn McCarney #include <gtest/gtest.h>
32472101c5SShawn McCarney
33472101c5SShawn McCarney using namespace phosphor::power::sequencer;
34472101c5SShawn McCarney
35472101c5SShawn McCarney using ::testing::Return;
36472101c5SShawn McCarney using ::testing::Throw;
37472101c5SShawn McCarney
38472101c5SShawn McCarney /**
39472101c5SShawn McCarney * @class StandardDeviceImpl
40472101c5SShawn McCarney *
41472101c5SShawn McCarney * Concrete subclass of the StandardDevice abstract class.
42472101c5SShawn McCarney *
43472101c5SShawn McCarney * This subclass is required for two reasons:
44472101c5SShawn McCarney * - StandardDevice has some pure virtual methods so it cannot be instantiated.
45472101c5SShawn McCarney * - The pure virtual methods provide the PMBus and GPIO information. Mocking
46472101c5SShawn McCarney * these makes it possible to test the pgood fault detection algorithm.
47472101c5SShawn McCarney *
48472101c5SShawn McCarney * This class is not intended to be used outside of this file. It is
49472101c5SShawn McCarney * implementation detail for testing the the StandardDevice class.
50472101c5SShawn McCarney */
51472101c5SShawn McCarney class StandardDeviceImpl : public StandardDevice
52472101c5SShawn McCarney {
53472101c5SShawn McCarney public:
54472101c5SShawn McCarney // Specify which compiler-generated methods we want
55472101c5SShawn McCarney StandardDeviceImpl() = delete;
56472101c5SShawn McCarney StandardDeviceImpl(const StandardDeviceImpl&) = delete;
57472101c5SShawn McCarney StandardDeviceImpl(StandardDeviceImpl&&) = delete;
58472101c5SShawn McCarney StandardDeviceImpl& operator=(const StandardDeviceImpl&) = delete;
59472101c5SShawn McCarney StandardDeviceImpl& operator=(StandardDeviceImpl&&) = delete;
60472101c5SShawn McCarney virtual ~StandardDeviceImpl() = default;
61472101c5SShawn McCarney
62472101c5SShawn McCarney // Constructor just calls StandardDevice constructor
StandardDeviceImpl(const std::string & name,std::vector<std::unique_ptr<Rail>> rails)63472101c5SShawn McCarney explicit StandardDeviceImpl(const std::string& name,
64472101c5SShawn McCarney std::vector<std::unique_ptr<Rail>> rails) :
65472101c5SShawn McCarney StandardDevice(name, std::move(rails))
66472101c5SShawn McCarney {}
67472101c5SShawn McCarney
68472101c5SShawn McCarney // Mock pure virtual methods
69fc3f31fbSShawn McCarney MOCK_METHOD(std::vector<int>, getGPIOValues, (Services & services),
70fc3f31fbSShawn McCarney (override));
71472101c5SShawn McCarney MOCK_METHOD(uint16_t, getStatusWord, (uint8_t page), (override));
72472101c5SShawn McCarney MOCK_METHOD(uint8_t, getStatusVout, (uint8_t page), (override));
73472101c5SShawn McCarney MOCK_METHOD(double, getReadVout, (uint8_t page), (override));
74472101c5SShawn McCarney MOCK_METHOD(double, getVoutUVFaultLimit, (uint8_t page), (override));
7516275831SShawn McCarney
7616275831SShawn McCarney // Override empty implementation with mock so we can verify it is called
7716275831SShawn McCarney MOCK_METHOD(void, prepareForPgoodFaultDetection, (Services & services),
7816275831SShawn McCarney (override));
79472101c5SShawn McCarney };
80472101c5SShawn McCarney
81472101c5SShawn McCarney /**
82472101c5SShawn McCarney * Creates a Rail object that checks for a pgood fault using STATUS_VOUT.
83472101c5SShawn McCarney *
84472101c5SShawn McCarney * @param name Unique name for the rail
85472101c5SShawn McCarney * @param isPowerSupplyRail Specifies whether the rail is produced by a
86472101c5SShawn McCarney power supply
87472101c5SShawn McCarney * @param pageNum PMBus PAGE number of the rail
88472101c5SShawn McCarney * @return Rail object
89472101c5SShawn McCarney */
createRailStatusVout(const std::string & name,bool isPowerSupplyRail,uint8_t pageNum)90*f5402197SPatrick Williams std::unique_ptr<Rail> createRailStatusVout(
91*f5402197SPatrick Williams const std::string& name, bool isPowerSupplyRail, uint8_t pageNum)
92472101c5SShawn McCarney {
93472101c5SShawn McCarney std::optional<std::string> presence{};
94472101c5SShawn McCarney std::optional<uint8_t> page{pageNum};
95472101c5SShawn McCarney bool checkStatusVout{true};
96472101c5SShawn McCarney bool compareVoltageToLimit{false};
97472101c5SShawn McCarney std::optional<GPIO> gpio{};
98472101c5SShawn McCarney return std::make_unique<Rail>(name, presence, page, isPowerSupplyRail,
99472101c5SShawn McCarney checkStatusVout, compareVoltageToLimit, gpio);
100472101c5SShawn McCarney }
101472101c5SShawn McCarney
102472101c5SShawn McCarney /**
103472101c5SShawn McCarney * Creates a Rail object that checks for a pgood fault using a GPIO.
104472101c5SShawn McCarney *
105472101c5SShawn McCarney * @param name Unique name for the rail
106472101c5SShawn McCarney * @param isPowerSupplyRail Specifies whether the rail is produced by a
107472101c5SShawn McCarney power supply
108472101c5SShawn McCarney * @param gpio GPIO line to read to determine the pgood status of the rail
109472101c5SShawn McCarney * @return Rail object
110472101c5SShawn McCarney */
createRailGPIO(const std::string & name,bool isPowerSupplyRail,unsigned int gpioLine)111*f5402197SPatrick Williams std::unique_ptr<Rail> createRailGPIO(
112*f5402197SPatrick Williams const std::string& name, bool isPowerSupplyRail, unsigned int gpioLine)
113472101c5SShawn McCarney {
114472101c5SShawn McCarney std::optional<std::string> presence{};
115472101c5SShawn McCarney std::optional<uint8_t> page{};
116472101c5SShawn McCarney bool checkStatusVout{false};
117472101c5SShawn McCarney bool compareVoltageToLimit{false};
118472101c5SShawn McCarney bool activeLow{false};
119472101c5SShawn McCarney std::optional<GPIO> gpio{GPIO{gpioLine, activeLow}};
120472101c5SShawn McCarney return std::make_unique<Rail>(name, presence, page, isPowerSupplyRail,
121472101c5SShawn McCarney checkStatusVout, compareVoltageToLimit, gpio);
122472101c5SShawn McCarney }
123472101c5SShawn McCarney
12416275831SShawn McCarney /**
12516275831SShawn McCarney * Creates a Rail object that checks for a pgood fault using output voltage.
12616275831SShawn McCarney *
12716275831SShawn McCarney * @param name Unique name for the rail
12816275831SShawn McCarney * @param isPowerSupplyRail Specifies whether the rail is produced by a
12916275831SShawn McCarney power supply
13016275831SShawn McCarney * @param pageNum PMBus PAGE number of the rail
13116275831SShawn McCarney * @return Rail object
13216275831SShawn McCarney */
createRailOutputVoltage(const std::string & name,bool isPowerSupplyRail,uint8_t pageNum)133*f5402197SPatrick Williams std::unique_ptr<Rail> createRailOutputVoltage(
134*f5402197SPatrick Williams const std::string& name, bool isPowerSupplyRail, uint8_t pageNum)
13516275831SShawn McCarney {
13616275831SShawn McCarney std::optional<std::string> presence{};
13716275831SShawn McCarney std::optional<uint8_t> page{pageNum};
13816275831SShawn McCarney bool checkStatusVout{false};
13916275831SShawn McCarney bool compareVoltageToLimit{true};
14016275831SShawn McCarney std::optional<GPIO> gpio{};
14116275831SShawn McCarney return std::make_unique<Rail>(name, presence, page, isPowerSupplyRail,
14216275831SShawn McCarney checkStatusVout, compareVoltageToLimit, gpio);
14316275831SShawn McCarney }
14416275831SShawn McCarney
TEST(StandardDeviceTests,Constructor)145472101c5SShawn McCarney TEST(StandardDeviceTests, Constructor)
146472101c5SShawn McCarney {
147472101c5SShawn McCarney // Empty vector of rails
148472101c5SShawn McCarney {
149472101c5SShawn McCarney std::vector<std::unique_ptr<Rail>> rails{};
150472101c5SShawn McCarney StandardDeviceImpl device{"xyz_pseq", std::move(rails)};
151472101c5SShawn McCarney
152472101c5SShawn McCarney EXPECT_EQ(device.getName(), "xyz_pseq");
153472101c5SShawn McCarney EXPECT_TRUE(device.getRails().empty());
154472101c5SShawn McCarney }
155472101c5SShawn McCarney
156472101c5SShawn McCarney // Non-empty vector of rails
157472101c5SShawn McCarney {
158472101c5SShawn McCarney std::vector<std::unique_ptr<Rail>> rails{};
159472101c5SShawn McCarney rails.emplace_back(createRailGPIO("PSU", true, 3));
16016275831SShawn McCarney rails.emplace_back(createRailOutputVoltage("VDD", false, 5));
161472101c5SShawn McCarney rails.emplace_back(createRailStatusVout("VIO", false, 7));
162472101c5SShawn McCarney StandardDeviceImpl device{"abc_pseq", std::move(rails)};
163472101c5SShawn McCarney
164472101c5SShawn McCarney EXPECT_EQ(device.getName(), "abc_pseq");
165472101c5SShawn McCarney EXPECT_EQ(device.getRails().size(), 3);
166472101c5SShawn McCarney EXPECT_EQ(device.getRails()[0]->getName(), "PSU");
167472101c5SShawn McCarney EXPECT_EQ(device.getRails()[1]->getName(), "VDD");
168472101c5SShawn McCarney EXPECT_EQ(device.getRails()[2]->getName(), "VIO");
169472101c5SShawn McCarney }
170472101c5SShawn McCarney }
171472101c5SShawn McCarney
TEST(StandardDeviceTests,GetName)172472101c5SShawn McCarney TEST(StandardDeviceTests, GetName)
173472101c5SShawn McCarney {
174472101c5SShawn McCarney std::vector<std::unique_ptr<Rail>> rails{};
175472101c5SShawn McCarney StandardDeviceImpl device{"xyz_pseq", std::move(rails)};
176472101c5SShawn McCarney
177472101c5SShawn McCarney EXPECT_EQ(device.getName(), "xyz_pseq");
178472101c5SShawn McCarney }
179472101c5SShawn McCarney
TEST(StandardDeviceTests,GetRails)180472101c5SShawn McCarney TEST(StandardDeviceTests, GetRails)
181472101c5SShawn McCarney {
182472101c5SShawn McCarney // Empty vector of rails
183472101c5SShawn McCarney {
184472101c5SShawn McCarney std::vector<std::unique_ptr<Rail>> rails{};
185472101c5SShawn McCarney StandardDeviceImpl device{"xyz_pseq", std::move(rails)};
186472101c5SShawn McCarney
187472101c5SShawn McCarney EXPECT_TRUE(device.getRails().empty());
188472101c5SShawn McCarney }
189472101c5SShawn McCarney
190472101c5SShawn McCarney // Non-empty vector of rails
191472101c5SShawn McCarney {
192472101c5SShawn McCarney std::vector<std::unique_ptr<Rail>> rails{};
193472101c5SShawn McCarney rails.emplace_back(createRailGPIO("PSU", true, 3));
19416275831SShawn McCarney rails.emplace_back(createRailOutputVoltage("VDD", false, 5));
195472101c5SShawn McCarney rails.emplace_back(createRailStatusVout("VIO", false, 7));
196472101c5SShawn McCarney StandardDeviceImpl device{"abc_pseq", std::move(rails)};
197472101c5SShawn McCarney
198472101c5SShawn McCarney EXPECT_EQ(device.getRails().size(), 3);
199472101c5SShawn McCarney EXPECT_EQ(device.getRails()[0]->getName(), "PSU");
200472101c5SShawn McCarney EXPECT_EQ(device.getRails()[1]->getName(), "VDD");
201472101c5SShawn McCarney EXPECT_EQ(device.getRails()[2]->getName(), "VIO");
202472101c5SShawn McCarney }
203472101c5SShawn McCarney }
204472101c5SShawn McCarney
TEST(StandardDeviceTests,FindPgoodFault)205472101c5SShawn McCarney TEST(StandardDeviceTests, FindPgoodFault)
206472101c5SShawn McCarney {
207472101c5SShawn McCarney // No rail has a pgood fault
208472101c5SShawn McCarney {
209472101c5SShawn McCarney std::vector<std::unique_ptr<Rail>> rails{};
210472101c5SShawn McCarney rails.emplace_back(createRailGPIO("PSU", true, 2));
21116275831SShawn McCarney rails.emplace_back(createRailOutputVoltage("VDD", false, 5));
212472101c5SShawn McCarney rails.emplace_back(createRailStatusVout("VIO", false, 7));
213472101c5SShawn McCarney StandardDeviceImpl device{"abc_pseq", std::move(rails)};
214472101c5SShawn McCarney
21516275831SShawn McCarney EXPECT_CALL(device, prepareForPgoodFaultDetection).Times(1);
216472101c5SShawn McCarney std::vector<int> gpioValues{1, 1, 1};
217472101c5SShawn McCarney EXPECT_CALL(device, getGPIOValues)
218472101c5SShawn McCarney .Times(1)
219472101c5SShawn McCarney .WillOnce(Return(gpioValues));
22016275831SShawn McCarney EXPECT_CALL(device, getReadVout(5)).Times(1).WillOnce(Return(1.2));
22116275831SShawn McCarney EXPECT_CALL(device, getVoutUVFaultLimit(5))
22216275831SShawn McCarney .Times(1)
22316275831SShawn McCarney .WillOnce(Return(1.1));
224472101c5SShawn McCarney EXPECT_CALL(device, getStatusVout(7)).Times(1).WillOnce(Return(0x00));
225472101c5SShawn McCarney
226472101c5SShawn McCarney MockServices services{};
227472101c5SShawn McCarney
228472101c5SShawn McCarney std::string powerSupplyError{};
229472101c5SShawn McCarney std::map<std::string, std::string> additionalData{};
230*f5402197SPatrick Williams std::string error =
231*f5402197SPatrick Williams device.findPgoodFault(services, powerSupplyError, additionalData);
232472101c5SShawn McCarney EXPECT_TRUE(error.empty());
233472101c5SShawn McCarney EXPECT_EQ(additionalData.size(), 0);
234472101c5SShawn McCarney }
235472101c5SShawn McCarney
23616275831SShawn McCarney // First rail has a pgood fault detected via GPIO
237472101c5SShawn McCarney // Is a PSU rail: No PSU error specified
238472101c5SShawn McCarney {
239472101c5SShawn McCarney std::vector<std::unique_ptr<Rail>> rails{};
240472101c5SShawn McCarney rails.emplace_back(createRailGPIO("PSU", true, 2));
24116275831SShawn McCarney rails.emplace_back(createRailOutputVoltage("VDD", false, 5));
242472101c5SShawn McCarney rails.emplace_back(createRailStatusVout("VIO", false, 7));
243472101c5SShawn McCarney StandardDeviceImpl device{"abc_pseq", std::move(rails)};
244472101c5SShawn McCarney
24516275831SShawn McCarney EXPECT_CALL(device, prepareForPgoodFaultDetection).Times(1);
246472101c5SShawn McCarney std::vector<int> gpioValues{1, 1, 0};
247472101c5SShawn McCarney EXPECT_CALL(device, getGPIOValues)
248472101c5SShawn McCarney .Times(1)
249472101c5SShawn McCarney .WillOnce(Return(gpioValues));
25016275831SShawn McCarney EXPECT_CALL(device, getReadVout(5)).Times(0);
25116275831SShawn McCarney EXPECT_CALL(device, getVoutUVFaultLimit(5)).Times(0);
25216275831SShawn McCarney EXPECT_CALL(device, getStatusVout(7)).Times(1).WillOnce(Return(0x00));
253472101c5SShawn McCarney
254472101c5SShawn McCarney MockServices services{};
255472101c5SShawn McCarney EXPECT_CALL(services,
256472101c5SShawn McCarney logInfoMsg("Device abc_pseq GPIO values: [1, 1, 0]"))
257472101c5SShawn McCarney .Times(1);
258472101c5SShawn McCarney EXPECT_CALL(
259472101c5SShawn McCarney services,
260472101c5SShawn McCarney logErrorMsg(
261472101c5SShawn McCarney "Pgood fault found in rail monitored by device abc_pseq"))
262472101c5SShawn McCarney .Times(1);
263472101c5SShawn McCarney EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail PSU"))
264472101c5SShawn McCarney .Times(1);
265472101c5SShawn McCarney EXPECT_CALL(
266472101c5SShawn McCarney services,
267472101c5SShawn McCarney logErrorMsg(
268472101c5SShawn McCarney "Rail PSU pgood GPIO line offset 2 has inactive value 0"))
269472101c5SShawn McCarney .Times(1);
270472101c5SShawn McCarney
271472101c5SShawn McCarney std::string powerSupplyError{};
272472101c5SShawn McCarney std::map<std::string, std::string> additionalData{};
273*f5402197SPatrick Williams std::string error =
274*f5402197SPatrick Williams device.findPgoodFault(services, powerSupplyError, additionalData);
275472101c5SShawn McCarney EXPECT_EQ(error,
276472101c5SShawn McCarney "xyz.openbmc_project.Power.Error.PowerSequencerVoltageFault");
277472101c5SShawn McCarney EXPECT_EQ(additionalData.size(), 5);
278472101c5SShawn McCarney EXPECT_EQ(additionalData["DEVICE_NAME"], "abc_pseq");
279472101c5SShawn McCarney EXPECT_EQ(additionalData["GPIO_VALUES"], "[1, 1, 0]");
280472101c5SShawn McCarney EXPECT_EQ(additionalData["RAIL_NAME"], "PSU");
281472101c5SShawn McCarney EXPECT_EQ(additionalData["GPIO_LINE"], "2");
282472101c5SShawn McCarney EXPECT_EQ(additionalData["GPIO_VALUE"], "0");
283472101c5SShawn McCarney }
284472101c5SShawn McCarney
28516275831SShawn McCarney // First rail has a pgood fault detected via GPIO
286472101c5SShawn McCarney // Is a PSU rail: PSU error specified
287472101c5SShawn McCarney {
288472101c5SShawn McCarney std::vector<std::unique_ptr<Rail>> rails{};
289472101c5SShawn McCarney rails.emplace_back(createRailGPIO("PSU", true, 2));
29016275831SShawn McCarney rails.emplace_back(createRailOutputVoltage("VDD", false, 5));
291472101c5SShawn McCarney rails.emplace_back(createRailStatusVout("VIO", false, 7));
292472101c5SShawn McCarney StandardDeviceImpl device{"abc_pseq", std::move(rails)};
293472101c5SShawn McCarney
29416275831SShawn McCarney EXPECT_CALL(device, prepareForPgoodFaultDetection).Times(1);
295472101c5SShawn McCarney std::vector<int> gpioValues{1, 1, 0};
296472101c5SShawn McCarney EXPECT_CALL(device, getGPIOValues)
297472101c5SShawn McCarney .Times(1)
298472101c5SShawn McCarney .WillOnce(Return(gpioValues));
29916275831SShawn McCarney EXPECT_CALL(device, getReadVout(5)).Times(0);
30016275831SShawn McCarney EXPECT_CALL(device, getVoutUVFaultLimit(5)).Times(0);
30116275831SShawn McCarney EXPECT_CALL(device, getStatusVout(7)).Times(1).WillOnce(Return(0x00));
302472101c5SShawn McCarney
303472101c5SShawn McCarney MockServices services{};
304472101c5SShawn McCarney EXPECT_CALL(services,
305472101c5SShawn McCarney logInfoMsg("Device abc_pseq GPIO values: [1, 1, 0]"))
306472101c5SShawn McCarney .Times(1);
307472101c5SShawn McCarney EXPECT_CALL(
308472101c5SShawn McCarney services,
309472101c5SShawn McCarney logErrorMsg(
310472101c5SShawn McCarney "Pgood fault found in rail monitored by device abc_pseq"))
311472101c5SShawn McCarney .Times(1);
312472101c5SShawn McCarney EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail PSU"))
313472101c5SShawn McCarney .Times(1);
314472101c5SShawn McCarney EXPECT_CALL(
315472101c5SShawn McCarney services,
316472101c5SShawn McCarney logErrorMsg(
317472101c5SShawn McCarney "Rail PSU pgood GPIO line offset 2 has inactive value 0"))
318472101c5SShawn McCarney .Times(1);
319472101c5SShawn McCarney
320472101c5SShawn McCarney std::string powerSupplyError{"Undervoltage fault: PSU1"};
321472101c5SShawn McCarney std::map<std::string, std::string> additionalData{};
322*f5402197SPatrick Williams std::string error =
323*f5402197SPatrick Williams device.findPgoodFault(services, powerSupplyError, additionalData);
324472101c5SShawn McCarney EXPECT_EQ(error, powerSupplyError);
325472101c5SShawn McCarney EXPECT_EQ(additionalData.size(), 5);
326472101c5SShawn McCarney EXPECT_EQ(additionalData["DEVICE_NAME"], "abc_pseq");
327472101c5SShawn McCarney EXPECT_EQ(additionalData["GPIO_VALUES"], "[1, 1, 0]");
328472101c5SShawn McCarney EXPECT_EQ(additionalData["RAIL_NAME"], "PSU");
329472101c5SShawn McCarney EXPECT_EQ(additionalData["GPIO_LINE"], "2");
330472101c5SShawn McCarney EXPECT_EQ(additionalData["GPIO_VALUE"], "0");
331472101c5SShawn McCarney }
332472101c5SShawn McCarney
33316275831SShawn McCarney // Second rail has a pgood fault detected via output voltage
334472101c5SShawn McCarney // Not a PSU rail: PSU error specified
335472101c5SShawn McCarney {
336472101c5SShawn McCarney std::vector<std::unique_ptr<Rail>> rails{};
337472101c5SShawn McCarney rails.emplace_back(createRailGPIO("PSU", true, 2));
33816275831SShawn McCarney rails.emplace_back(createRailOutputVoltage("VDD", false, 5));
339472101c5SShawn McCarney rails.emplace_back(createRailStatusVout("VIO", false, 7));
340472101c5SShawn McCarney StandardDeviceImpl device{"abc_pseq", std::move(rails)};
341472101c5SShawn McCarney
34216275831SShawn McCarney EXPECT_CALL(device, prepareForPgoodFaultDetection).Times(1);
343472101c5SShawn McCarney std::vector<int> gpioValues{1, 1, 1};
344472101c5SShawn McCarney EXPECT_CALL(device, getGPIOValues)
345472101c5SShawn McCarney .Times(1)
346472101c5SShawn McCarney .WillOnce(Return(gpioValues));
34716275831SShawn McCarney EXPECT_CALL(device, getReadVout(5)).Times(1).WillOnce(Return(1.1));
34816275831SShawn McCarney EXPECT_CALL(device, getVoutUVFaultLimit(5))
34916275831SShawn McCarney .Times(1)
35016275831SShawn McCarney .WillOnce(Return(1.2));
35116275831SShawn McCarney EXPECT_CALL(device, getStatusVout(7)).Times(1).WillOnce(Return(0x00));
352472101c5SShawn McCarney EXPECT_CALL(device, getStatusWord(5)).Times(1).WillOnce(Return(0xbeef));
353472101c5SShawn McCarney
354472101c5SShawn McCarney MockServices services{};
355472101c5SShawn McCarney EXPECT_CALL(services,
356472101c5SShawn McCarney logInfoMsg("Device abc_pseq GPIO values: [1, 1, 1]"))
357472101c5SShawn McCarney .Times(1);
358472101c5SShawn McCarney EXPECT_CALL(
359472101c5SShawn McCarney services,
360472101c5SShawn McCarney logErrorMsg(
361472101c5SShawn McCarney "Pgood fault found in rail monitored by device abc_pseq"))
362472101c5SShawn McCarney .Times(1);
363472101c5SShawn McCarney EXPECT_CALL(services, logInfoMsg("Rail VDD STATUS_WORD: 0xbeef"))
364472101c5SShawn McCarney .Times(1);
365472101c5SShawn McCarney EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD"))
366472101c5SShawn McCarney .Times(1);
367472101c5SShawn McCarney EXPECT_CALL(
368472101c5SShawn McCarney services,
36916275831SShawn McCarney logErrorMsg(
37016275831SShawn McCarney "Rail VDD output voltage 1.1V is <= UV fault limit 1.2V"))
371472101c5SShawn McCarney .Times(1);
372472101c5SShawn McCarney
373472101c5SShawn McCarney std::string powerSupplyError{"Undervoltage fault: PSU1"};
374472101c5SShawn McCarney std::map<std::string, std::string> additionalData{};
375*f5402197SPatrick Williams std::string error =
376*f5402197SPatrick Williams device.findPgoodFault(services, powerSupplyError, additionalData);
377472101c5SShawn McCarney EXPECT_EQ(error,
378472101c5SShawn McCarney "xyz.openbmc_project.Power.Error.PowerSequencerVoltageFault");
37916275831SShawn McCarney EXPECT_EQ(additionalData.size(), 6);
380472101c5SShawn McCarney EXPECT_EQ(additionalData["DEVICE_NAME"], "abc_pseq");
381472101c5SShawn McCarney EXPECT_EQ(additionalData["GPIO_VALUES"], "[1, 1, 1]");
382472101c5SShawn McCarney EXPECT_EQ(additionalData["RAIL_NAME"], "VDD");
38316275831SShawn McCarney EXPECT_EQ(additionalData["READ_VOUT"], "1.1");
38416275831SShawn McCarney EXPECT_EQ(additionalData["VOUT_UV_FAULT_LIMIT"], "1.2");
385472101c5SShawn McCarney EXPECT_EQ(additionalData["STATUS_WORD"], "0xbeef");
386472101c5SShawn McCarney }
387472101c5SShawn McCarney
38816275831SShawn McCarney // Third rail has a pgood fault detected via STATUS_VOUT
389472101c5SShawn McCarney // Device returns 0 GPIO values
390472101c5SShawn McCarney // Does not halt pgood fault detection because GPIO values not used by rails
391472101c5SShawn McCarney {
392472101c5SShawn McCarney std::vector<std::unique_ptr<Rail>> rails{};
393472101c5SShawn McCarney rails.emplace_back(createRailStatusVout("PSU", true, 3));
39416275831SShawn McCarney rails.emplace_back(createRailOutputVoltage("VDD", false, 5));
395472101c5SShawn McCarney rails.emplace_back(createRailStatusVout("VIO", false, 7));
396472101c5SShawn McCarney StandardDeviceImpl device{"abc_pseq", std::move(rails)};
397472101c5SShawn McCarney
39816275831SShawn McCarney EXPECT_CALL(device, prepareForPgoodFaultDetection).Times(1);
399472101c5SShawn McCarney std::vector<int> gpioValues{};
400472101c5SShawn McCarney EXPECT_CALL(device, getGPIOValues)
401472101c5SShawn McCarney .Times(1)
402472101c5SShawn McCarney .WillOnce(Return(gpioValues));
403472101c5SShawn McCarney EXPECT_CALL(device, getStatusVout(3)).Times(1).WillOnce(Return(0x00));
40416275831SShawn McCarney EXPECT_CALL(device, getReadVout(5)).Times(0);
40516275831SShawn McCarney EXPECT_CALL(device, getVoutUVFaultLimit(5)).Times(0);
406472101c5SShawn McCarney EXPECT_CALL(device, getStatusVout(7)).Times(1).WillOnce(Return(0x11));
407472101c5SShawn McCarney EXPECT_CALL(device, getStatusWord(7)).Times(1).WillOnce(Return(0xbeef));
408472101c5SShawn McCarney
409472101c5SShawn McCarney MockServices services{};
410472101c5SShawn McCarney EXPECT_CALL(
411472101c5SShawn McCarney services,
412472101c5SShawn McCarney logErrorMsg(
413472101c5SShawn McCarney "Pgood fault found in rail monitored by device abc_pseq"))
414472101c5SShawn McCarney .Times(1);
415472101c5SShawn McCarney EXPECT_CALL(services, logInfoMsg("Rail VIO STATUS_WORD: 0xbeef"))
416472101c5SShawn McCarney .Times(1);
417472101c5SShawn McCarney EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VIO"))
418472101c5SShawn McCarney .Times(1);
419472101c5SShawn McCarney EXPECT_CALL(
420472101c5SShawn McCarney services,
421472101c5SShawn McCarney logErrorMsg("Rail VIO has fault bits set in STATUS_VOUT: 0x11"))
422472101c5SShawn McCarney .Times(1);
423472101c5SShawn McCarney
424472101c5SShawn McCarney std::string powerSupplyError{};
425472101c5SShawn McCarney std::map<std::string, std::string> additionalData{};
426*f5402197SPatrick Williams std::string error =
427*f5402197SPatrick Williams device.findPgoodFault(services, powerSupplyError, additionalData);
428472101c5SShawn McCarney EXPECT_EQ(error,
429472101c5SShawn McCarney "xyz.openbmc_project.Power.Error.PowerSequencerVoltageFault");
430472101c5SShawn McCarney EXPECT_EQ(additionalData.size(), 4);
431472101c5SShawn McCarney EXPECT_EQ(additionalData["DEVICE_NAME"], "abc_pseq");
432472101c5SShawn McCarney EXPECT_EQ(additionalData["RAIL_NAME"], "VIO");
433472101c5SShawn McCarney EXPECT_EQ(additionalData["STATUS_VOUT"], "0x11");
434472101c5SShawn McCarney EXPECT_EQ(additionalData["STATUS_WORD"], "0xbeef");
435472101c5SShawn McCarney }
436472101c5SShawn McCarney
43716275831SShawn McCarney // Third rail has a pgood fault detected via STATUS_VOUT
438472101c5SShawn McCarney // Exception occurs trying to obtain GPIO values from device
439472101c5SShawn McCarney // Does not halt pgood fault detection because GPIO values not used by rails
440472101c5SShawn McCarney {
441472101c5SShawn McCarney std::vector<std::unique_ptr<Rail>> rails{};
442472101c5SShawn McCarney rails.emplace_back(createRailStatusVout("PSU", true, 3));
44316275831SShawn McCarney rails.emplace_back(createRailOutputVoltage("VDD", false, 5));
444472101c5SShawn McCarney rails.emplace_back(createRailStatusVout("VIO", false, 7));
445472101c5SShawn McCarney StandardDeviceImpl device{"abc_pseq", std::move(rails)};
446472101c5SShawn McCarney
44716275831SShawn McCarney EXPECT_CALL(device, prepareForPgoodFaultDetection).Times(1);
448472101c5SShawn McCarney EXPECT_CALL(device, getGPIOValues)
449472101c5SShawn McCarney .Times(1)
450472101c5SShawn McCarney .WillOnce(Throw(std::runtime_error{"Unable to acquire GPIO line"}));
451472101c5SShawn McCarney EXPECT_CALL(device, getStatusVout(3)).Times(1).WillOnce(Return(0x00));
45216275831SShawn McCarney EXPECT_CALL(device, getReadVout(5)).Times(0);
45316275831SShawn McCarney EXPECT_CALL(device, getVoutUVFaultLimit(5)).Times(0);
454472101c5SShawn McCarney EXPECT_CALL(device, getStatusVout(7)).Times(1).WillOnce(Return(0x11));
455472101c5SShawn McCarney EXPECT_CALL(device, getStatusWord(7)).Times(1).WillOnce(Return(0xbeef));
456472101c5SShawn McCarney
457472101c5SShawn McCarney MockServices services{};
458472101c5SShawn McCarney EXPECT_CALL(
459472101c5SShawn McCarney services,
460472101c5SShawn McCarney logErrorMsg(
461472101c5SShawn McCarney "Pgood fault found in rail monitored by device abc_pseq"))
462472101c5SShawn McCarney .Times(1);
463472101c5SShawn McCarney EXPECT_CALL(services, logInfoMsg("Rail VIO STATUS_WORD: 0xbeef"))
464472101c5SShawn McCarney .Times(1);
465472101c5SShawn McCarney EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VIO"))
466472101c5SShawn McCarney .Times(1);
467472101c5SShawn McCarney EXPECT_CALL(
468472101c5SShawn McCarney services,
469472101c5SShawn McCarney logErrorMsg("Rail VIO has fault bits set in STATUS_VOUT: 0x11"))
470472101c5SShawn McCarney .Times(1);
471472101c5SShawn McCarney
472472101c5SShawn McCarney std::string powerSupplyError{};
473472101c5SShawn McCarney std::map<std::string, std::string> additionalData{};
474*f5402197SPatrick Williams std::string error =
475*f5402197SPatrick Williams device.findPgoodFault(services, powerSupplyError, additionalData);
476472101c5SShawn McCarney EXPECT_EQ(error,
477472101c5SShawn McCarney "xyz.openbmc_project.Power.Error.PowerSequencerVoltageFault");
478472101c5SShawn McCarney EXPECT_EQ(additionalData.size(), 4);
479472101c5SShawn McCarney EXPECT_EQ(additionalData["DEVICE_NAME"], "abc_pseq");
480472101c5SShawn McCarney EXPECT_EQ(additionalData["RAIL_NAME"], "VIO");
481472101c5SShawn McCarney EXPECT_EQ(additionalData["STATUS_VOUT"], "0x11");
482472101c5SShawn McCarney EXPECT_EQ(additionalData["STATUS_WORD"], "0xbeef");
483472101c5SShawn McCarney }
484472101c5SShawn McCarney
48516275831SShawn McCarney // All three rails appear to have a pgood fault. Verify third rail is
48616275831SShawn McCarney // selected, even though it is last in the power on sequence, because it is
48716275831SShawn McCarney // checked using STATUS_VOUT. That check happens before the other checks.
48816275831SShawn McCarney {
48916275831SShawn McCarney std::vector<std::unique_ptr<Rail>> rails{};
49016275831SShawn McCarney rails.emplace_back(createRailGPIO("PSU", true, 2));
49116275831SShawn McCarney rails.emplace_back(createRailGPIO("VDD", false, 1));
49216275831SShawn McCarney rails.emplace_back(createRailStatusVout("VIO", false, 7));
49316275831SShawn McCarney StandardDeviceImpl device{"abc_pseq", std::move(rails)};
49416275831SShawn McCarney
49516275831SShawn McCarney EXPECT_CALL(device, prepareForPgoodFaultDetection).Times(1);
49616275831SShawn McCarney std::vector<int> gpioValues{0, 0, 0};
49716275831SShawn McCarney EXPECT_CALL(device, getGPIOValues)
49816275831SShawn McCarney .Times(1)
49916275831SShawn McCarney .WillOnce(Return(gpioValues));
50016275831SShawn McCarney EXPECT_CALL(device, getStatusVout(7)).Times(1).WillOnce(Return(0x11));
50116275831SShawn McCarney EXPECT_CALL(device, getStatusWord(7)).Times(1).WillOnce(Return(0xbeef));
50216275831SShawn McCarney
50316275831SShawn McCarney MockServices services{};
50416275831SShawn McCarney EXPECT_CALL(services,
50516275831SShawn McCarney logInfoMsg("Device abc_pseq GPIO values: [0, 0, 0]"))
50616275831SShawn McCarney .Times(1);
50716275831SShawn McCarney EXPECT_CALL(
50816275831SShawn McCarney services,
50916275831SShawn McCarney logErrorMsg(
51016275831SShawn McCarney "Pgood fault found in rail monitored by device abc_pseq"))
51116275831SShawn McCarney .Times(1);
51216275831SShawn McCarney EXPECT_CALL(services, logInfoMsg("Rail VIO STATUS_WORD: 0xbeef"))
51316275831SShawn McCarney .Times(1);
51416275831SShawn McCarney EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VIO"))
51516275831SShawn McCarney .Times(1);
51616275831SShawn McCarney EXPECT_CALL(
51716275831SShawn McCarney services,
51816275831SShawn McCarney logErrorMsg("Rail VIO has fault bits set in STATUS_VOUT: 0x11"))
51916275831SShawn McCarney .Times(1);
52016275831SShawn McCarney
52116275831SShawn McCarney std::string powerSupplyError{};
52216275831SShawn McCarney std::map<std::string, std::string> additionalData{};
523*f5402197SPatrick Williams std::string error =
524*f5402197SPatrick Williams device.findPgoodFault(services, powerSupplyError, additionalData);
52516275831SShawn McCarney EXPECT_EQ(error,
52616275831SShawn McCarney "xyz.openbmc_project.Power.Error.PowerSequencerVoltageFault");
52716275831SShawn McCarney EXPECT_EQ(additionalData.size(), 5);
52816275831SShawn McCarney EXPECT_EQ(additionalData["DEVICE_NAME"], "abc_pseq");
52916275831SShawn McCarney EXPECT_EQ(additionalData["GPIO_VALUES"], "[0, 0, 0]");
53016275831SShawn McCarney EXPECT_EQ(additionalData["RAIL_NAME"], "VIO");
53116275831SShawn McCarney EXPECT_EQ(additionalData["STATUS_VOUT"], "0x11");
53216275831SShawn McCarney EXPECT_EQ(additionalData["STATUS_WORD"], "0xbeef");
53316275831SShawn McCarney }
53416275831SShawn McCarney
53516275831SShawn McCarney // Two rails appear to have a pgood fault. One is found via output voltage
53616275831SShawn McCarney // and one is found via a GPIO. Verify the first rail in the sequence with
53716275831SShawn McCarney // a fault is selected.
53816275831SShawn McCarney {
53916275831SShawn McCarney std::vector<std::unique_ptr<Rail>> rails{};
54016275831SShawn McCarney rails.emplace_back(createRailStatusVout("VIO", false, 7));
54116275831SShawn McCarney rails.emplace_back(createRailOutputVoltage("VDD", false, 5));
54216275831SShawn McCarney rails.emplace_back(createRailGPIO("PSU", true, 2));
54316275831SShawn McCarney StandardDeviceImpl device{"abc_pseq", std::move(rails)};
54416275831SShawn McCarney
54516275831SShawn McCarney EXPECT_CALL(device, prepareForPgoodFaultDetection).Times(1);
54616275831SShawn McCarney std::vector<int> gpioValues{1, 1, 0};
54716275831SShawn McCarney EXPECT_CALL(device, getGPIOValues)
54816275831SShawn McCarney .Times(1)
54916275831SShawn McCarney .WillOnce(Return(gpioValues));
55016275831SShawn McCarney EXPECT_CALL(device, getStatusVout(7)).Times(1).WillOnce(Return(0x00));
55116275831SShawn McCarney EXPECT_CALL(device, getReadVout(5)).Times(1).WillOnce(Return(1.1));
55216275831SShawn McCarney EXPECT_CALL(device, getVoutUVFaultLimit(5))
55316275831SShawn McCarney .Times(1)
55416275831SShawn McCarney .WillOnce(Return(1.2));
55516275831SShawn McCarney EXPECT_CALL(device, getStatusWord(5)).Times(1).WillOnce(Return(0xbeef));
55616275831SShawn McCarney
55716275831SShawn McCarney MockServices services{};
55816275831SShawn McCarney EXPECT_CALL(services,
55916275831SShawn McCarney logInfoMsg("Device abc_pseq GPIO values: [1, 1, 0]"))
56016275831SShawn McCarney .Times(1);
56116275831SShawn McCarney EXPECT_CALL(
56216275831SShawn McCarney services,
56316275831SShawn McCarney logErrorMsg(
56416275831SShawn McCarney "Pgood fault found in rail monitored by device abc_pseq"))
56516275831SShawn McCarney .Times(1);
56616275831SShawn McCarney EXPECT_CALL(services, logInfoMsg("Rail VDD STATUS_WORD: 0xbeef"))
56716275831SShawn McCarney .Times(1);
56816275831SShawn McCarney EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD"))
56916275831SShawn McCarney .Times(1);
57016275831SShawn McCarney EXPECT_CALL(
57116275831SShawn McCarney services,
57216275831SShawn McCarney logErrorMsg(
57316275831SShawn McCarney "Rail VDD output voltage 1.1V is <= UV fault limit 1.2V"))
57416275831SShawn McCarney .Times(1);
57516275831SShawn McCarney
57616275831SShawn McCarney std::string powerSupplyError{};
57716275831SShawn McCarney std::map<std::string, std::string> additionalData{};
578*f5402197SPatrick Williams std::string error =
579*f5402197SPatrick Williams device.findPgoodFault(services, powerSupplyError, additionalData);
58016275831SShawn McCarney EXPECT_EQ(error,
58116275831SShawn McCarney "xyz.openbmc_project.Power.Error.PowerSequencerVoltageFault");
58216275831SShawn McCarney EXPECT_EQ(additionalData.size(), 6);
58316275831SShawn McCarney EXPECT_EQ(additionalData["DEVICE_NAME"], "abc_pseq");
58416275831SShawn McCarney EXPECT_EQ(additionalData["GPIO_VALUES"], "[1, 1, 0]");
58516275831SShawn McCarney EXPECT_EQ(additionalData["RAIL_NAME"], "VDD");
58616275831SShawn McCarney EXPECT_EQ(additionalData["READ_VOUT"], "1.1");
58716275831SShawn McCarney EXPECT_EQ(additionalData["VOUT_UV_FAULT_LIMIT"], "1.2");
58816275831SShawn McCarney EXPECT_EQ(additionalData["STATUS_WORD"], "0xbeef");
58916275831SShawn McCarney }
59016275831SShawn McCarney
591472101c5SShawn McCarney // Exception is thrown during pgood fault detection
592472101c5SShawn McCarney {
593472101c5SShawn McCarney std::vector<std::unique_ptr<Rail>> rails{};
594472101c5SShawn McCarney rails.emplace_back(createRailGPIO("PSU", true, 2));
59516275831SShawn McCarney rails.emplace_back(createRailOutputVoltage("VDD", false, 5));
596472101c5SShawn McCarney rails.emplace_back(createRailStatusVout("VIO", false, 7));
597472101c5SShawn McCarney StandardDeviceImpl device{"abc_pseq", std::move(rails)};
598472101c5SShawn McCarney
59916275831SShawn McCarney EXPECT_CALL(device, prepareForPgoodFaultDetection).Times(1);
600472101c5SShawn McCarney std::vector<int> gpioValues{1, 1, 1};
601472101c5SShawn McCarney EXPECT_CALL(device, getGPIOValues)
602472101c5SShawn McCarney .Times(1)
603472101c5SShawn McCarney .WillOnce(Return(gpioValues));
60416275831SShawn McCarney EXPECT_CALL(device, getReadVout(5)).Times(0);
60516275831SShawn McCarney EXPECT_CALL(device, getVoutUVFaultLimit(5)).Times(0);
60616275831SShawn McCarney EXPECT_CALL(device, getStatusVout(7))
607472101c5SShawn McCarney .Times(1)
608472101c5SShawn McCarney .WillOnce(Throw(std::runtime_error{"File does not exist"}));
609472101c5SShawn McCarney
610472101c5SShawn McCarney MockServices services{};
611472101c5SShawn McCarney
612472101c5SShawn McCarney std::string powerSupplyError{};
613472101c5SShawn McCarney std::map<std::string, std::string> additionalData{};
614472101c5SShawn McCarney try
615472101c5SShawn McCarney {
616472101c5SShawn McCarney device.findPgoodFault(services, powerSupplyError, additionalData);
617472101c5SShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
618472101c5SShawn McCarney }
619472101c5SShawn McCarney catch (const std::exception& e)
620472101c5SShawn McCarney {
621472101c5SShawn McCarney EXPECT_STREQ(
622472101c5SShawn McCarney e.what(),
623472101c5SShawn McCarney "Unable to determine if a pgood fault occurred in device abc_pseq: "
62416275831SShawn McCarney "Unable to read STATUS_VOUT value for rail VIO: "
625472101c5SShawn McCarney "File does not exist");
626472101c5SShawn McCarney }
627472101c5SShawn McCarney }
628472101c5SShawn McCarney }
629